diff --git a/Makefile.am b/Makefile.am
index f18f3549e261761f974ba0263147ee336d1ba2b3..1cdfc99f1eb8f4ad3726d71d7d032bded6456371 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -18,7 +18,7 @@ nobase_dist_graphtooldoc_DATA = \
doc/draw.rst \
doc/index.rst \
doc/spectral.rst \
- doc/community.rst \
+ doc/inference.rst \
doc/flow.rst \
doc/Makefile \
doc/quickstart.rst \
@@ -30,7 +30,6 @@ nobase_dist_graphtooldoc_DATA = \
doc/topology.rst \
doc/conf.py \
doc/pyenv.py \
- doc/community.xml \
doc/search_example.xml \
doc/sphinxext/README.txt \
doc/sphinxext/LICENSE.txt \
diff --git a/configure.ac b/configure.ac
index b044e9d302486bebcff3e1d2e2dd35266d683094..b6bda80eaf05eb155c5decc70d6518b634b0392c 100644
--- a/configure.ac
+++ b/configure.ac
@@ -457,11 +457,12 @@ src/Makefile
src/graph/Makefile
src/graph/centrality/Makefile
src/graph/clustering/Makefile
-src/graph/community/Makefile
+src/graph/community_old/Makefile
src/graph/correlations/Makefile
src/graph/draw/Makefile
src/graph/flow/Makefile
src/graph/generation/Makefile
+src/graph/inference/Makefile
src/graph/layout/Makefile
src/graph/search/Makefile
src/graph/spectral/Makefile
diff --git a/doc/community.rst b/doc/community.rst
deleted file mode 100644
index ae1cbdab12e8760e05078b50855b005648911d99..0000000000000000000000000000000000000000
--- a/doc/community.rst
+++ /dev/null
@@ -1,27 +0,0 @@
-.. automodule:: graph_tool.community
- :no-members:
- :no-undoc-members:
-
- .. autofunction:: minimize_blockmodel_dl
- .. autoclass:: BlockState
- .. autoclass:: OverlapBlockState
- .. autoclass:: CovariateBlockState
- .. autofunction:: mcmc_sweep
- .. autofunction:: multilevel_minimize
- .. autofunction:: collect_edge_marginals
- .. autofunction:: collect_vertex_marginals
- .. autofunction:: mf_entropy
- .. autofunction:: bethe_entropy
- .. autofunction:: model_entropy
- .. autofunction:: get_max_B
- .. autofunction:: get_akc
- .. autofunction:: condensation_graph
- .. autofunction:: minimize_nested_blockmodel_dl
- .. autoclass:: NestedBlockState
- .. autofunction:: init_nested_state
- .. autofunction:: nested_mcmc_sweep
- .. autofunction:: nested_tree_sweep
- .. autofunction:: get_hierarchy_tree
- .. autofunction:: get_block_edge_gradient
- .. autofunction:: community_structure
- .. autofunction:: modularity
diff --git a/doc/community.xml b/doc/community.xml
deleted file mode 100644
index d0a41332bcba8a603ced64232e34ab8f8174abc4..0000000000000000000000000000000000000000
--- a/doc/community.xml
+++ /dev/null
@@ -1,12562 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
- 0x1.ep+5, 0x1.ep+5
-
-
- 0x1.ep+5, 0x1.4p+6
-
-
- 0x1.ep+5, 0x1.9p+6
-
-
- 0x1.ep+5, 0x1.ep+6
-
-
- 0x1.ep+5, 0x1.18p+7
-
-
- 0x1.ep+5, 0x1.4p+7
-
-
- 0x1.ep+5, 0x1.68p+7
-
-
- 0x1.ep+5, 0x1.9p+7
-
-
- 0x1.4p+6, 0x1.ep+5
-
-
- 0x1.4p+6, 0x1.4p+6
-
-
- 0x1.4p+6, 0x1.9p+6
-
-
- 0x1.4p+6, 0x1.ep+6
-
-
- 0x1.4p+6, 0x1.18p+7
-
-
- 0x1.4p+6, 0x1.4p+7
-
-
- 0x1.4p+6, 0x1.68p+7
-
-
- 0x1.4p+6, 0x1.9p+7
-
-
- 0x1.9p+6, 0x1.ep+5
-
-
- 0x1.9p+6, 0x1.4p+6
-
-
- 0x1.9p+6, 0x1.9p+6
-
-
- 0x1.9p+6, 0x1.ep+6
-
-
- 0x1.9p+6, 0x1.18p+7
-
-
- 0x1.9p+6, 0x1.4p+7
-
-
- 0x1.9p+6, 0x1.68p+7
-
-
- 0x1.9p+6, 0x1.9p+7
-
-
- 0x1.ep+6, 0x1.ep+5
-
-
- 0x1.ep+6, 0x1.4p+6
-
-
- 0x1.ep+6, 0x1.9p+6
-
-
- 0x1.ep+6, 0x1.ep+6
-
-
- 0x1.ep+6, 0x1.18p+7
-
-
- 0x1.ep+6, 0x1.4p+7
-
-
- 0x1.ep+6, 0x1.68p+7
-
-
- 0x1.ep+6, 0x1.9p+7
-
-
- 0x1.18p+7, 0x1.ep+5
-
-
- 0x1.18p+7, 0x1.4p+6
-
-
- 0x1.18p+7, 0x1.9p+6
-
-
- 0x1.18p+7, 0x1.ep+6
-
-
- 0x1.18p+7, 0x1.18p+7
-
-
- 0x1.18p+7, 0x1.4p+7
-
-
- 0x1.18p+7, 0x1.68p+7
-
-
- 0x1.18p+7, 0x1.9p+7
-
-
- 0x1.4p+7, 0x1.ep+5
-
-
- 0x1.4p+7, 0x1.4p+6
-
-
- 0x1.4p+7, 0x1.9p+6
-
-
- 0x1.4p+7, 0x1.ep+6
-
-
- 0x1.4p+7, 0x1.18p+7
-
-
- 0x1.4p+7, 0x1.4p+7
-
-
- 0x1.4p+7, 0x1.68p+7
-
-
- 0x1.4p+7, 0x1.9p+7
-
-
- 0x1.68p+7, 0x1.ep+5
-
-
- 0x1.68p+7, 0x1.4p+6
-
-
- 0x1.68p+7, 0x1.9p+6
-
-
- 0x1.68p+7, 0x1.ep+6
-
-
- 0x1.68p+7, 0x1.18p+7
-
-
- 0x1.68p+7, 0x1.4p+7
-
-
- 0x1.68p+7, 0x1.68p+7
-
-
- 0x1.68p+7, 0x1.9p+7
-
-
- 0x1.9p+7, 0x1.ep+5
-
-
- 0x1.9p+7, 0x1.4p+6
-
-
- 0x1.9p+7, 0x1.9p+6
-
-
- 0x1.9p+7, 0x1.ep+6
-
-
- 0x1.9p+7, 0x1.18p+7
-
-
- 0x1.9p+7, 0x1.4p+7
-
-
- 0x1.9p+7, 0x1.68p+7
-
-
- 0x1.9p+7, 0x1.9p+7
-
-
- 0x1.4p+8, 0x1.54p+8
-
-
- 0x1.9p+6, 0x1.2cp+8
-
-
- 0x1.9p+7, 0x1.04p+8
-
-
- 0x1.68p+8, 0x1.68p+7
-
-
- 0x1.54p+8, 0x1.68p+8
-
-
- 0x1.b8p+7, 0x1.ep+6
-
-
- 0x1.ep+6, 0x1.2cp+8
-
-
- 0x1.b8p+7, 0x1.9p+7
-
-
- 0x1.04p+8, 0x1.ep+6
-
-
- 0x1.68p+7, 0x1.18p+8
-
-
- 0x1.ep+7, 0x1.54p+8
-
-
- 0x1.04p+8, 0x1.4p+7
-
-
- 0x1.4p+8, 0x1.18p+7
-
-
- 0x1.04p+8, 0x1.04p+8
-
-
- 0x1.04p+8, 0x1.54p+8
-
-
- 0x1.18p+7, 0x1.ep+7
-
-
- 0x1.ep+5, 0x1.18p+8
-
-
- 0x1.ep+6, 0x1.68p+8
-
-
- 0x1.04p+8, 0x1.4p+6
-
-
- 0x1.18p+8, 0x1.ep+7
-
-
- 0x1.68p+8, 0x1.9p+7
-
-
- 0x1.4p+8, 0x1.4p+6
-
-
- 0x1.68p+7, 0x1.54p+8
-
-
- 0x1.54p+8, 0x1.18p+8
-
-
- 0x1.2cp+8, 0x1.68p+8
-
-
- 0x1.2cp+8, 0x1.4p+7
-
-
- 0x1.54p+8, 0x1.9p+7
-
-
- 0x1.4p+6, 0x1.04p+8
-
-
- 0x1.9p+6, 0x1.4p+8
-
-
- 0x1.04p+8, 0x1.18p+8
-
-
- 0x1.b8p+7, 0x1.4p+7
-
-
- 0x1.ep+6, 0x1.ep+7
-
-
- 0x1.18p+8, 0x1.9p+6
-
-
- 0x1.2cp+8, 0x1.ep+7
-
-
- 0x1.04p+8, 0x1.b8p+7
-
-
- 0x1.ep+5, 0x1.2cp+8
-
-
- 0x1.18p+8, 0x1.18p+8
-
-
- 0x1.4p+7, 0x1.54p+8
-
-
- 0x1.ep+5, 0x1.04p+8
-
-
- 0x1.4p+8, 0x1.2cp+8
-
-
- 0x1.ep+6, 0x1.04p+8
-
-
- 0x1.68p+8, 0x1.4p+8
-
-
- 0x1.18p+8, 0x1.4p+8
-
-
- 0x1.04p+8, 0x1.2cp+8
-
-
- 0x1.18p+8, 0x1.2cp+8
-
-
- 0x1.ep+7, 0x1.ep+5
-
-
- 0x1.68p+7, 0x1.04p+8
-
-
- 0x1.ep+7, 0x1.9p+7
-
-
- 0x1.4p+8, 0x1.ep+7
-
-
- 0x1.68p+7, 0x1.2cp+8
-
-
- 0x1.54p+8, 0x1.9p+6
-
-
- 0x1.ep+7, 0x1.4p+8
-
-
- 0x1.b8p+7, 0x1.4p+6
-
-
- 0x1.4p+7, 0x1.2cp+8
-
-
- 0x1.2cp+8, 0x1.18p+8
-
-
- 0x1.68p+8, 0x1.54p+8
-
-
- 0x1.18p+8, 0x1.68p+8
-
-
- 0x1.9p+7, 0x1.ep+7
-
-
- 0x1.2cp+8, 0x1.54p+8
-
-
- 0x1.2cp+8, 0x1.4p+6
-
-
- 0x1.9p+6, 0x1.68p+8
-
-
- 0x1.54p+8, 0x1.4p+7
-
-
- 0x1.18p+8, 0x1.b8p+7
-
-
- 0x1.ep+5, 0x1.ep+7
-
-
- 0x1.18p+7, 0x1.04p+8
-
-
- 0x1.68p+8, 0x1.4p+6
-
-
- 0x1.68p+8, 0x1.4p+7
-
-
- 0x1.68p+8, 0x1.ep+5
-
-
- 0x1.68p+8, 0x1.b8p+7
-
-
- 0x1.b8p+7, 0x1.ep+5
-
-
- 0x1.54p+8, 0x1.2cp+8
-
-
- 0x1.ep+6, 0x1.b8p+7
-
-
- 0x1.54p+8, 0x1.ep+6
-
-
- 0x1.9p+6, 0x1.04p+8
-
-
- 0x1.b8p+7, 0x1.2cp+8
-
-
- 0x1.9p+7, 0x1.18p+8
-
-
- 0x1.4p+7, 0x1.68p+8
-
-
- 0x1.ep+7, 0x1.4p+7
-
-
- 0x1.4p+6, 0x1.68p+8
-
-
- 0x1.ep+7, 0x1.68p+7
-
-
- 0x1.18p+8, 0x1.4p+7
-
-
- 0x1.4p+7, 0x1.b8p+7
-
-
- 0x1.ep+7, 0x1.04p+8
-
-
- 0x1.04p+8, 0x1.9p+7
-
-
- 0x1.b8p+7, 0x1.18p+8
-
-
- 0x1.04p+8, 0x1.68p+7
-
-
- 0x1.18p+8, 0x1.9p+7
-
-
- 0x1.68p+8, 0x1.ep+6
-
-
- 0x1.2cp+8, 0x1.68p+7
-
-
- 0x1.b8p+7, 0x1.04p+8
-
-
- 0x1.04p+8, 0x1.ep+7
-
-
- 0x1.68p+7, 0x1.ep+7
-
-
- 0x1.9p+6, 0x1.ep+7
-
-
- 0x1.18p+8, 0x1.ep+6
-
-
- 0x1.ep+6, 0x1.4p+8
-
-
- 0x1.4p+7, 0x1.4p+8
-
-
- 0x1.b8p+7, 0x1.54p+8
-
-
- 0x1.9p+7, 0x1.4p+8
-
-
- 0x1.54p+8, 0x1.54p+8
-
-
- 0x1.18p+7, 0x1.b8p+7
-
-
- 0x1.18p+8, 0x1.ep+5
-
-
- 0x1.ep+6, 0x1.18p+8
-
-
- 0x1.ep+5, 0x1.68p+8
-
-
- 0x1.ep+5, 0x1.54p+8
-
-
- 0x1.b8p+7, 0x1.4p+8
-
-
- 0x1.18p+7, 0x1.4p+8
-
-
- 0x1.68p+8, 0x1.18p+7
-
-
- 0x1.b8p+7, 0x1.ep+7
-
-
- 0x1.9p+7, 0x1.68p+8
-
-
- 0x1.68p+8, 0x1.18p+8
-
-
- 0x1.ep+7, 0x1.2cp+8
-
-
- 0x1.4p+8, 0x1.68p+7
-
-
- 0x1.ep+7, 0x1.ep+7
-
-
- 0x1.9p+6, 0x1.54p+8
-
-
- 0x1.9p+7, 0x1.2cp+8
-
-
- 0x1.54p+8, 0x1.04p+8
-
-
- 0x1.4p+6, 0x1.b8p+7
-
-
- 0x1.4p+8, 0x1.18p+8
-
-
- 0x1.2cp+8, 0x1.4p+8
-
-
- 0x1.68p+8, 0x1.9p+6
-
-
- 0x1.2cp+8, 0x1.9p+6
-
-
- 0x1.18p+8, 0x1.18p+7
-
-
- 0x1.2cp+8, 0x1.ep+6
-
-
- 0x1.18p+7, 0x1.68p+8
-
-
- 0x1.4p+8, 0x1.b8p+7
-
-
- 0x1.ep+7, 0x1.18p+7
-
-
- 0x1.54p+8, 0x1.4p+8
-
-
- 0x1.54p+8, 0x1.ep+7
-
-
- 0x1.ep+5, 0x1.4p+8
-
-
- 0x1.4p+8, 0x1.4p+7
-
-
- 0x1.4p+7, 0x1.04p+8
-
-
- 0x1.68p+8, 0x1.04p+8
-
-
- 0x1.ep+7, 0x1.4p+6
-
-
- 0x1.54p+8, 0x1.68p+7
-
-
- 0x1.4p+8, 0x1.9p+6
-
-
- 0x1.9p+6, 0x1.b8p+7
-
-
- 0x1.4p+6, 0x1.2cp+8
-
-
- 0x1.4p+8, 0x1.ep+6
-
-
- 0x1.ep+7, 0x1.b8p+7
-
-
- 0x1.b8p+7, 0x1.18p+7
-
-
- 0x1.18p+8, 0x1.4p+6
-
-
- 0x1.b8p+7, 0x1.b8p+7
-
-
- 0x1.68p+8, 0x1.2cp+8
-
-
- 0x1.9p+7, 0x1.54p+8
-
-
- 0x1.54p+8, 0x1.4p+6
-
-
- 0x1.68p+8, 0x1.68p+8
-
-
- 0x1.2cp+8, 0x1.04p+8
-
-
- 0x1.4p+7, 0x1.18p+8
-
-
- 0x1.18p+7, 0x1.2cp+8
-
-
- 0x1.2cp+8, 0x1.b8p+7
-
-
- 0x1.68p+7, 0x1.b8p+7
-
-
- 0x1.ep+7, 0x1.9p+6
-
-
- 0x1.68p+8, 0x1.ep+7
-
-
- 0x1.68p+7, 0x1.68p+8
-
-
- 0x1.04p+8, 0x1.68p+8
-
-
- 0x1.04p+8, 0x1.18p+7
-
-
- 0x1.b8p+7, 0x1.68p+8
-
-
- 0x1.ep+7, 0x1.18p+8
-
-
- 0x1.54p+8, 0x1.ep+5
-
-
- 0x1.4p+6, 0x1.4p+8
-
-
- 0x1.2cp+8, 0x1.2cp+8
-
-
- 0x1.18p+7, 0x1.18p+8
-
-
- 0x1.54p+8, 0x1.b8p+7
-
-
- 0x1.ep+7, 0x1.ep+6
-
-
- 0x1.4p+8, 0x1.4p+8
-
-
- 0x1.2cp+8, 0x1.9p+7
-
-
- 0x1.18p+8, 0x1.68p+7
-
-
- 0x1.4p+6, 0x1.54p+8
-
-
- 0x1.ep+6, 0x1.54p+8
-
-
- 0x1.4p+8, 0x1.68p+8
-
-
- 0x1.04p+8, 0x1.4p+8
-
-
- 0x1.04p+8, 0x1.ep+5
-
-
- 0x1.4p+8, 0x1.9p+7
-
-
- 0x1.4p+6, 0x1.ep+7
-
-
- 0x1.18p+7, 0x1.54p+8
-
-
- 0x1.4p+7, 0x1.ep+7
-
-
- 0x1.b8p+7, 0x1.68p+7
-
-
- 0x1.9p+6, 0x1.18p+8
-
-
- 0x1.2cp+8, 0x1.ep+5
-
-
- 0x1.4p+6, 0x1.18p+8
-
-
- 0x1.18p+8, 0x1.54p+8
-
-
- 0x1.54p+8, 0x1.18p+7
-
-
- 0x1.ep+7, 0x1.68p+8
-
-
- 0x1.4p+8, 0x1.ep+5
-
-
- 0x1.4p+8, 0x1.04p+8
-
-
- 0x1.18p+8, 0x1.04p+8
-
-
- 0x1.04p+8, 0x1.9p+6
-
-
- 0x1.2cp+8, 0x1.18p+7
-
-
- 0x1.9p+7, 0x1.b8p+7
-
-
- 0x1.68p+7, 0x1.4p+8
-
-
- 0x1.ep+5, 0x1.b8p+7
-
-
- 0x1.b8p+7, 0x1.9p+6
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/doc/graph_tool.rst b/doc/graph_tool.rst
index 4f0e30f6da82b9f3da59de4c96cad6b03a960501..de7e5f4229415fea58ec39b3018b152ad9ca6dbb 100644
--- a/doc/graph_tool.rst
+++ b/doc/graph_tool.rst
@@ -207,11 +207,11 @@ Available subpackages
centrality
clustering
collection
- community
correlations
draw
flow
generation
+ inference
search_module
spectral
stats
diff --git a/doc/inference.rst b/doc/inference.rst
new file mode 100644
index 0000000000000000000000000000000000000000..9dec439fe2748a6e448c761966589fdee34c2390
--- /dev/null
+++ b/doc/inference.rst
@@ -0,0 +1,1160 @@
+.. automodule:: graph_tool.inference
+ :no-undoc-members:
+ :show-inheritance:
+
+.. testcode:: inference_detailed
+ :hide:
+
+ import test_inference
+
+.. testoutput:: inference_detailed
+ :hide:
+ :options: -ELLIPSIS, +NORMALIZE_WHITESPACE
+
+ directed: True overlap: False layered: False deg-corr: False dl: False
+ mcmc (unweighted)
+ (653.7368247664258, 100) 72
+ mcmc
+ (709.1284329780722, 103) 67
+ (26.555814693961594, 102) 68
+ (-108.54759577258069, 115) 73
+ merge
+ (327.7692003897153, 50)
+ (240.08404807493113, 110)
+ (80.17105004298814, 115)
+ shrink
+ 5
+
+ directed: True overlap: False layered: False deg-corr: False dl: True
+ mcmc (unweighted)
+ (37.79906768205631, 105) 77
+ mcmc
+ (55.97800577471912, 107) 72
+ (-83.84539912129875, 99) 61
+ (60.363819212130494, 114) 73
+ merge
+ (-403.6228272212937, 50)
+ (-2.5333139051913243, 104)
+ (19.27758710817686, 115)
+ shrink
+ 5
+
+ directed: True overlap: False layered: False deg-corr: True dl: False
+ mcmc (unweighted)
+ (448.9786966541199, 102) 79
+ mcmc
+ (523.3965114137179, 106) 74
+ (-25.920853037839876, 103) 74
+ (25.289255024521793, 113) 74
+ merge
+ (277.5286735275392, 50)
+ (358.72935230058386, 101)
+ (-115.7860369979704, 115)
+ shrink
+ 5
+
+ directed: True overlap: False layered: False deg-corr: True dl: True
+ mcmc (unweighted)
+ (-370.02300429105844, 97) 68
+ mcmc
+ (-236.5251583848658, 104) 77
+ (-90.66222214522463, 104) 71
+ (22.38348339446021, 112) 72
+ merge
+ (-747.2417795796297, 50)
+ (-137.5051248827061, 100)
+ (-22.19343083384164, 113)
+ shrink
+ 5
+
+ directed: True overlap: False layered: covariates deg-corr: False dl: False
+ mcmc (unweighted)
+ (676.3594764878382, 114) 72
+ mcmc
+ (659.612425515866, 109) 73
+ (-7.114556958148668, 115) 75
+ (12.450844591087305, 115) 73
+ merge
+ (546.8411931837169, 50)
+ (446.7766774894063, 111)
+ (-233.62505581815967, 115)
+ shrink
+ 5
+
+ directed: True overlap: False layered: covariates deg-corr: False dl: True
+ mcmc (unweighted)
+ (11.134477993729128, 113) 71
+ mcmc
+ (39.69116889632038, 110) 70
+ (23.949240858672248, 114) 72
+ (-20.311156765735674, 115) 75
+ merge
+ (-185.8315002121304, 50)
+ (-8.659869616217907, 113)
+ (7.1698821344710115, 114)
+ shrink
+ 5
+
+ directed: True overlap: False layered: covariates deg-corr: True dl: False
+ mcmc (unweighted)
+ (625.1252715930277, 113) 70
+ mcmc
+ (687.1284762185751, 113) 64
+ (88.17735417358503, 113) 59
+ (-267.6672513613203, 114) 73
+ merge
+ (461.52365374179743, 50)
+ (554.2643481837697, 109)
+ (-311.10773578568643, 114)
+ shrink
+ 5
+
+ directed: True overlap: False layered: covariates deg-corr: True dl: True
+ mcmc (unweighted)
+ (-265.4943379846294, 111) 76
+ mcmc
+ (-260.48845827199153, 115) 75
+ (-41.58828679977694, 114) 72
+ (20.07067071778924, 114) 74
+ merge
+ (-584.6644045599711, 50)
+ (-124.7745711915025, 112)
+ (70.39505964132627, 115)
+ shrink
+ 5
+
+ directed: True overlap: False layered: True deg-corr: False dl: False
+ mcmc (unweighted)
+ (649.827058787757, 109) 63
+ mcmc
+ (460.97415340386925, 115) 74
+ (20.20550023851644, 113) 71
+ (-11.482268963688943, 114) 75
+ merge
+ (382.0710697233173, 50)
+ (659.1089055216413, 112)
+ (-384.8843394117986, 115)
+ shrink
+ 5
+
+ directed: True overlap: False layered: True deg-corr: False dl: True
+ mcmc (unweighted)
+ (-146.93776337069448, 114) 67
+ mcmc
+ (-118.54952723454903, 112) 67
+ (-22.25121342666771, 111) 70
+ (0.09101846869118524, 113) 72
+ merge
+ (-345.98550748381786, 50)
+ (-19.856093212550192, 111)
+ (24.406541323617336, 115)
+ shrink
+ 5
+
+ directed: True overlap: False layered: True deg-corr: True dl: False
+ mcmc (unweighted)
+ (299.47637000759045, 113) 71
+ mcmc
+ (339.7882309572504, 113) 73
+ (-22.951725336949753, 113) 70
+ (-71.18214115859378, 115) 76
+ merge
+ (112.65674339105865, 50)
+ (270.7282008346159, 115)
+ (-48.227031269529164, 115)
+ shrink
+ 5
+
+ directed: True overlap: False layered: True deg-corr: True dl: True
+ mcmc (unweighted)
+ (-489.54010405218867, 115) 72
+ mcmc
+ (-477.0610489947019, 115) 73
+ (-44.315852689841975, 111) 70
+ (-6.031490138403797, 113) 70
+ merge
+ (-694.3072536306113, 50)
+ (-260.61832985101154, 112)
+ (32.31080727878356, 115)
+ shrink
+ 5
+
+ directed: True overlap: True layered: False deg-corr: False dl: False
+ mcmc (unweighted)
+ (684.2122420163477, 1222) 784
+ (-14.493178594335856, 1340) 787
+ merge
+ (0.0, 50)
+ shrink
+ 5
+
+ directed: True overlap: True layered: False deg-corr: False dl: True
+ mcmc (unweighted)
+ (-451.273408828854, 1223) 777
+ (-27.657518258027803, 1340) 769
+ merge
+ (-308.96675893350766, 50)
+ shrink
+ 5
+
+ directed: True overlap: True layered: False deg-corr: True dl: False
+ mcmc (unweighted)
+ (410.11174108492406, 1226) 756
+ (-11.783502069519063, 1337) 760
+ merge
+ (1.3862943611198906, 50)
+ shrink
+ 5
+
+ directed: True overlap: True layered: False deg-corr: True dl: True
+ mcmc (unweighted)
+ (-160.75919034773452, 1225) 785
+ (-37.94994320552587, 1340) 763
+ merge
+ (-326.8859937813693, 50)
+ shrink
+ 5
+
+ directed: True overlap: True layered: covariates deg-corr: False dl: False
+ mcmc (unweighted)
+ (6.4407729047092115, 1197) 115
+ (15.090003687444668, 1306) 115
+ merge
+ (-53.01104703350246, 50)
+ shrink
+ 5
+
+ directed: True overlap: True layered: covariates deg-corr: False dl: True
+ mcmc (unweighted)
+ (0.7469127360648091, 1189) 115
+ (-4.454066106756823, 1307) 115
+ merge
+ (-1060.3966480302265, 50)
+ shrink
+ 5
+
+ directed: True overlap: True layered: covariates deg-corr: True dl: False
+ mcmc (unweighted)
+ (19.34655635911719, 1201) 115
+ (13.021627155555198, 1302) 115
+ merge
+ (139.75704771951064, 50)
+ shrink
+ 5
+
+ directed: True overlap: True layered: covariates deg-corr: True dl: True
+ mcmc (unweighted)
+ (-42.609890899551715, 1196) 115
+ (-20.85691258865186, 1310) 115
+ merge
+ (-1234.0387385376016, 50)
+ shrink
+ 5
+
+ directed: True overlap: True layered: True deg-corr: False dl: False
+ mcmc (unweighted)
+ (-32.53034167952721, 1201) 115
+ (56.45069492553456, 1294) 115
+ merge
+ (-114.8981755030546, 50)
+ shrink
+ 5
+
+ directed: True overlap: True layered: True deg-corr: False dl: True
+ mcmc (unweighted)
+ (-1.035017095430904, 1191) 115
+ (-4.378896497938934, 1305) 115
+ merge
+ (-993.1502579858155, 50)
+ shrink
+ 5
+
+ directed: True overlap: True layered: True deg-corr: True dl: False
+ mcmc (unweighted)
+ (6.508901229588357, 1189) 115
+ (-13.11412599497536, 1301) 115
+ merge
+ (-77.33333924925819, 50)
+ shrink
+ 5
+
+ directed: True overlap: True layered: True deg-corr: True dl: True
+ mcmc (unweighted)
+ (62.56398098817939, 1195) 115
+ (-3.5377428709883647, 1304) 115
+ merge
+ (-1052.7716211643888, 50)
+ shrink
+ 5
+
+ directed: False overlap: False layered: False deg-corr: False dl: False
+ mcmc (unweighted)
+ (693.169084122821, 106) 69
+ mcmc
+ (575.1255994230743, 106) 74
+ (-18.268855666875268, 102) 74
+ (84.23562085572648, 114) 68
+ merge
+ (254.062569976686, 50)
+ (294.07064838987327, 108)
+ (-35.54039844306018, 115)
+ shrink
+ 5
+
+ directed: False overlap: False layered: False deg-corr: False dl: True
+ mcmc (unweighted)
+ (6.089470037990972, 99) 74
+ mcmc
+ (31.337138743014393, 96) 71
+ (-32.348734568160104, 94) 68
+ (11.13293108914912, 114) 73
+ merge
+ (-452.35567315108005, 50)
+ (-14.94414868569813, 108)
+ (-26.47985161842624, 115)
+ shrink
+ 5
+
+ directed: False overlap: False layered: False deg-corr: True dl: False
+ mcmc (unweighted)
+ (474.71492598670625, 100) 79
+ mcmc
+ (575.0190616712077, 103) 74
+ (35.03115802167634, 99) 72
+ (-44.92187114668639, 114) 73
+ merge
+ (249.97743129324903, 50)
+ (425.23174309430004, 110)
+ (-159.32783404320577, 114)
+ shrink
+ 5
+
+ directed: False overlap: False layered: False deg-corr: True dl: True
+ mcmc (unweighted)
+ (-193.2001940253293, 99) 74
+ mcmc
+ (-174.90080436460175, 102) 76
+ (-39.52484390424932, 104) 72
+ (48.052018152160485, 113) 72
+ merge
+ (-717.2044026904009, 50)
+ (-71.77424635033832, 105)
+ (-25.114234051660894, 114)
+ shrink
+ 5
+
+ directed: False overlap: False layered: covariates deg-corr: False dl: False
+ mcmc (unweighted)
+ (772.5453980570721, 114) 67
+ mcmc
+ (720.1691858052512, 112) 69
+ (68.31407337248119, 111) 65
+ (-146.74986338638587, 114) 72
+ merge
+ (473.38852115957025, 50)
+ (376.67392866586084, 114)
+ (1.1626252512182127, 114)
+ shrink
+ 5
+
+ directed: False overlap: False layered: covariates deg-corr: False dl: True
+ mcmc (unweighted)
+ (39.60067070934042, 115) 72
+ mcmc
+ (-9.194100392728705, 115) 77
+ (23.758390517950442, 110) 75
+ (7.399872077643064, 115) 78
+ merge
+ (-254.49516803072956, 50)
+ (-9.215586113589342, 112)
+ (23.632624271547694, 112)
+ shrink
+ 5
+
+ directed: False overlap: False layered: covariates deg-corr: True dl: False
+ mcmc (unweighted)
+ (679.6815899057593, 111) 70
+ mcmc
+ (737.5066421528536, 114) 68
+ (-41.630424206875865, 111) 68
+ (-71.64216522170558, 114) 73
+ merge
+ (483.74983009336034, 50)
+ (465.972158053492, 114)
+ (-168.20407971455091, 114)
+ shrink
+ 5
+
+ directed: False overlap: False layered: covariates deg-corr: True dl: True
+ mcmc (unweighted)
+ (-246.9705243300452, 113) 67
+ mcmc
+ (-236.51398935319358, 113) 68
+ (83.02986995537107, 113) 78
+ (-33.29065578699246, 114) 73
+ merge
+ (-504.63687228651776, 50)
+ (-171.50178946195857, 108)
+ (49.50677409599346, 113)
+ shrink
+ 5
+
+ directed: False overlap: False layered: True deg-corr: False dl: False
+ mcmc (unweighted)
+ (540.8663037198617, 113) 68
+ mcmc
+ (507.7047847062117, 115) 69
+ (-56.73592493601191, 113) 74
+ (14.478960856237514, 114) 75
+ merge
+ (385.119877617005, 50)
+ (609.4426771976545, 112)
+ (-95.63740447873565, 114)
+ shrink
+ 5
+
+ directed: False overlap: False layered: True deg-corr: False dl: True
+ mcmc (unweighted)
+ (-135.48400339347597, 114) 69
+ mcmc
+ (-177.55059658149057, 112) 67
+ (77.30739145915234, 114) 77
+ (-37.788312169996864, 115) 78
+ merge
+ (-378.09608309928564, 50)
+ (-9.759576031614198, 114)
+ (-0.9536321167456725, 115)
+ shrink
+ 5
+
+ directed: False overlap: False layered: True deg-corr: True dl: False
+ mcmc (unweighted)
+ (416.8858712424856, 114) 72
+ mcmc
+ (543.6668155389088, 115) 65
+ (-116.88680318312439, 114) 78
+ (64.10454898532073, 114) 70
+ merge
+ (344.14747553149675, 50)
+ (395.5036614885022, 112)
+ (-144.23929897210388, 115)
+ shrink
+ 5
+
+ directed: False overlap: False layered: True deg-corr: True dl: True
+ mcmc (unweighted)
+ (-515.0632865530644, 114) 71
+ mcmc
+ (-429.52721402339705, 112) 75
+ (-97.8538715008062, 110) 69
+ (61.234048124156786, 115) 73
+ merge
+ (-750.3186792142322, 50)
+ (-289.89054259425507, 109)
+ (117.72715613340667, 115)
+ shrink
+ 5
+
+ directed: False overlap: True layered: False deg-corr: False dl: False
+ mcmc (unweighted)
+ (668.3427656597461, 1225) 785
+ (25.29309657374884, 1337) 773
+ merge
+ (0.0, 50)
+ shrink
+ 5
+
+ directed: False overlap: True layered: False deg-corr: False dl: True
+ mcmc (unweighted)
+ (-454.0663525173459, 1223) 770
+ (-3.768593665481344, 1341) 772
+ merge
+ (-302.1438895586243, 50)
+ shrink
+ 5
+
+ directed: False overlap: True layered: False deg-corr: True dl: False
+ mcmc (unweighted)
+ (715.484682404301, 1225) 765
+ (-34.61523962571205, 1341) 784
+ merge
+ (34.77514206365362, 50)
+ shrink
+ 5
+
+ directed: False overlap: True layered: False deg-corr: True dl: True
+ mcmc (unweighted)
+ (51.108409710889575, 1226) 775
+ (-5.747478822563901, 1338) 771
+ merge
+ (-288.7443154032152, 50)
+ shrink
+ 5
+
+ directed: False overlap: True layered: covariates deg-corr: False dl: False
+ mcmc (unweighted)
+ (30.51641860515133, 1198) 115
+ (-10.213872530535728, 1312) 115
+ merge
+ (-279.91158404351484, 50)
+ shrink
+ 5
+
+ directed: False overlap: True layered: covariates deg-corr: False dl: True
+ mcmc (unweighted)
+ (-47.83809678456382, 1197) 115
+ (30.994946483584556, 1306) 115
+ merge
+ (-1451.2844212406185, 50)
+ shrink
+ 5
+
+ directed: False overlap: True layered: covariates deg-corr: True dl: False
+ mcmc (unweighted)
+ (17.114695467713297, 1193) 115
+ (6.74992551722728, 1308) 115
+ merge
+ (-141.66901107706147, 50)
+ shrink
+ 5
+
+ directed: False overlap: True layered: covariates deg-corr: True dl: True
+ mcmc (unweighted)
+ (18.28144731527671, 1186) 115
+ (-8.899892485955935, 1320) 115
+ merge
+ (-2351.4411047024337, 50)
+ shrink
+ 5
+
+ directed: False overlap: True layered: True deg-corr: False dl: False
+ mcmc (unweighted)
+ (-30.414601069667068, 1192) 115
+ (23.38533942611877, 1317) 115
+ merge
+ (-160.6578412585288, 50)
+ shrink
+ 5
+
+ directed: False overlap: True layered: True deg-corr: False dl: True
+ mcmc (unweighted)
+ (-15.9501258457887, 1185) 115
+ (43.8463674972257, 1312) 115
+ merge
+ (-1100.5828201139577, 50)
+ shrink
+ 5
+
+ directed: False overlap: True layered: True deg-corr: True dl: False
+ mcmc (unweighted)
+ (38.98178711619759, 1197) 115
+ (18.742075941875243, 1319) 115
+ merge
+ (-116.24155086445886, 50)
+ shrink
+ 5
+
+ directed: False overlap: True layered: True deg-corr: True dl: True
+ mcmc (unweighted)
+ (-0.7081085763732451, 1190) 115
+ (-31.565140167020655, 1307) 115
+ merge
+ (-1350.8161986552966, 50)
+ shrink
+ 5
+
+ directed: True overlap: False layered: False deg-corr: False
+ Current bracket: (1, 60, 115) (2495.8290836444471, 3204.2321625907725, 3708.414497288833)
+ Current bracket: (1, 26, 60) (2495.8290836444471, 2617.8774215566509, 3204.2321625907725)
+ Current bracket: (1, 13, 26) (2495.8290836444471, 2363.1981701253062, 2617.8774215566509)
+ Current bracket: (1, 13, 26) (2495.8290836444471, 2363.1981701253062, 2617.8774215566509)
+ Bisect at B = 18 with S = 2453.367089312351
+ Current bracket: (1, 13, 18) (2495.8290836444471, 2363.1981701253062, 2453.3670893123513)
+ Bisect at B = 8 with S = 2300.994045668983
+ Current bracket: (1, 8, 13) (2495.8290836444471, 2300.9940456689828, 2363.1981701253062)
+ Bisect at B = 5 with S = 2285.052011050861
+ Current bracket: (1, 5, 8) (2495.8290836444471, 2285.052011050861, 2300.9940456689828)
+ Bisect at B = 3 with S = 2317.091178612431
+ Current bracket: (3, 5, 8) (2317.0911786124307, 2285.052011050861, 2300.9940456689828)
+ Bisect at B = 6 with S = 2284.866879995794
+ Current bracket: (5, 6, 8) (2285.052011050861, 2284.8668799957941, 2300.9940456689828)
+ Bisect at B = 7 with S = 2294.655787376431
+ Current bracket: (5, 6, 7) (2285.052011050861, 2284.8668799957941, 2294.6557873764309)
+ Bisect at B = 5 with S = 2285.052011050861
+ Best result: B = 6, S = 2284.866879995794
+ 6 2284.86688
+ level 1 : rejected replacement (1, 1) -> (1, 1) , dS: 0.0
+ level 1 : rejected insert 1 , dS: 0.0
+ level 0 : replaced (115, 1) -> (115, 5) , dS: -210.777072594 2
+ level 1 : replaced (5, 1) -> (5, 2) , dS: -2.66350792975 2
+ level 2 : rejected replacement (2, 1) -> (2, 1) , dS: 0.0
+ level 2 : rejected insert 2 , dS: 1.79175946923
+ level 1 : skipping 2
+ level 0 : replaced (115, 5) -> (115, 8) , dS: -5.91339284569 3
+ level 1 : rejected replacement (8, 2) -> (8, 2) , dS: 0.0
+ level 1 : rejected insert 8 , dS: 19.3741100228
+ level 0 : skipping 8
+ l: 0, N: 115, B: 8
+ l: 1, N: 8, B: 2
+ l: 2, N: 2, B: 1
+ 2276.47511028
+
+ directed: True overlap: False layered: False deg-corr: True
+ Current bracket: (1, 60, 115) (2318.8696624551153, 3051.6877329249223, 3337.5708321100378)
+ Current bracket: (1, 26, 60) (2318.8696624551153, 2579.1905163091492, 3051.6877329249223)
+ Current bracket: (1, 13, 26) (2318.8696624551153, 2292.6909131845441, 2579.1905163091492)
+ Current bracket: (1, 13, 26) (2318.8696624551153, 2292.6909131845441, 2579.1905163091492)
+ Bisect at B = 18 with S = 2424.807155254194
+ Current bracket: (1, 13, 18) (2318.8696624551153, 2292.6909131845441, 2424.8071552541942)
+ Bisect at B = 8 with S = 2196.047650916988
+ Current bracket: (1, 8, 13) (2318.8696624551153, 2196.0476509169875, 2292.6909131845441)
+ Bisect at B = 5 with S = 2165.076125813918
+ Current bracket: (1, 5, 8) (2318.8696624551153, 2165.0761258139182, 2196.0476509169875)
+ Bisect at B = 3 with S = 2178.869483800998
+ Current bracket: (3, 5, 8) (2178.8694838009978, 2165.0761258139182, 2196.0476509169875)
+ Bisect at B = 6 with S = 2170.665883964396
+ Current bracket: (3, 5, 6) (2178.8694838009978, 2165.0761258139182, 2170.665883964396)
+ Bisect at B = 4 with S = 2164.554037334525
+ Best result: B = 4, S = 2164.554037334525
+ 4 2164.55403733
+ level 1 : rejected replacement (1, 1) -> (1, 1) , dS: 0.0
+ level 1 : rejected insert 1 , dS: 0.0
+ level 0 : replaced (115, 1) -> (115, 4) , dS: -158.455012563 2
+ level 1 : replaced (4, 1) -> (4, 2) , dS: -0.230629487184 2
+ level 2 : rejected replacement (2, 1) -> (2, 1) , dS: 0.0
+ level 2 : rejected insert 2 , dS: 1.79175946923
+ level 1 : skipping 2
+ level 0 : rejected replacement (115, 4) -> (115, 5) , dS: 1.88971212096
+ l: 0, N: 115, B: 4
+ l: 1, N: 4, B: 2
+ l: 2, N: 2, B: 1
+ 2160.1840204
+
+ directed: True overlap: False layered: covariates deg-corr: False
+ Current bracket: (1, 60, 115) (3876.323037275662, 4770.369390710639, 5076.3584970855154)
+ Current bracket: (1, 26, 60) (3876.323037275662, 4390.4129518186537, 4770.369390710639)
+ Current bracket: (1, 13, 26) (3876.323037275662, 4090.8678102257359, 4390.4129518186537)
+ Current bracket: (1, 8, 13) (3876.323037275662, 3928.4123438440784, 4090.8678102257359)
+ Current bracket: (1, 5, 8) (3876.323037275662, 3815.3301172970105, 3928.4123438440784)
+ Current bracket: (1, 5, 8) (3876.323037275662, 3815.3301172970105, 3928.4123438440784)
+ Bisect at B = 3 with S = 3770.207464051877
+ Current bracket: (1, 3, 5) (3876.323037275662, 3770.2074640518772, 3815.3301172970105)
+ Bisect at B = 2 with S = 3787.213321435399
+ Current bracket: (2, 3, 5) (3787.2133214353989, 3770.2074640518772, 3815.3301172970105)
+ Bisect at B = 4 with S = 3781.892332292212
+ Current bracket: (2, 3, 4) (3787.2133214353989, 3770.2074640518772, 3781.8923322922124)
+ Bisect at B = 2 with S = 3787.213321435399
+ Best result: B = 3, S = 3770.207464051877
+ 3 3770.20746405
+ level 1 : rejected replacement (1, 1) -> (1, 1) , dS: 0.0
+ level 1 : rejected insert 1 , dS: 0.0
+ level 0 : replaced (115, 1) -> (115, 6) , dS: -201.16791632 2
+ level 1 : rejected replacement (6, 1) -> (6, 1) , dS: 0.0
+ level 1 : rejected insert 6 , dS: 12.7148161031
+ level 0 : skipping 6
+ l: 0, N: 115, B: 6
+ l: 1, N: 6, B: 1
+ 3675.15512096
+
+ directed: True overlap: False layered: covariates deg-corr: True
+ Current bracket: (1, 60, 115) (3699.3636160863302, 4524.7650859192672, 4705.5148319067212)
+ Current bracket: (1, 26, 60) (3699.3636160863302, 4280.5863383999085, 4524.7650859192672)
+ Current bracket: (1, 13, 26) (3699.3636160863302, 4013.0275490563249, 4280.5863383999085)
+ Current bracket: (1, 8, 13) (3699.3636160863302, 3825.7420416344448, 4013.0275490563249)
+ Current bracket: (1, 5, 8) (3699.3636160863302, 3716.3154093581552, 3825.7420416344448)
+ Current bracket: (1, 3, 5) (3699.3636160863302, 3636.3009795251073, 3716.3154093581552)
+ Current bracket: (1, 3, 5) (3699.3636160863302, 3636.3009795251073, 3716.3154093581552)
+ Bisect at B = 2 with S = 3638.452352760167
+ Current bracket: (2, 3, 5) (3638.4523527601673, 3636.3009795251073, 3716.3154093581552)
+ Bisect at B = 4 with S = 3673.832571602863
+ Current bracket: (2, 3, 4) (3638.4523527601673, 3636.3009795251073, 3673.8325716028635)
+ Bisect at B = 2 with S = 3638.452352760167
+ Best result: B = 3, S = 3636.300979525107
+ 3 3636.30097953
+ level 1 : rejected replacement (1, 1) -> (1, 1) , dS: 0.0
+ level 1 : rejected insert 1 , dS: 0.0
+ level 0 : replaced (115, 1) -> (115, 5) , dS: -150.163186164 2
+ level 1 : rejected replacement (5, 1) -> (5, 1) , dS: 0.0
+ level 1 : rejected insert 5 , dS: 9.62377364973
+ level 0 : skipping 5
+ l: 0, N: 115, B: 5
+ l: 1, N: 5, B: 1
+ 3549.20042992
+
+ directed: True overlap: False layered: True deg-corr: False
+ Current bracket: (1, 60, 115) (4149.3841336310379, 5284.3845874087538, 5806.3692226513531)
+ Current bracket: (1, 26, 60) (4149.3841336310379, 4970.2156440906747, 5284.3845874087538)
+ Current bracket: (1, 13, 26) (4149.3841336310379, 4665.913218701382, 4970.2156440906747)
+ Current bracket: (1, 8, 13) (4149.3841336310379, 4448.1593590070361, 4665.913218701382)
+ Current bracket: (1, 5, 8) (4149.3841336310379, 4259.415534978637, 4448.1593590070361)
+ Current bracket: (1, 3, 5) (4149.3841336310379, 4156.7168613952836, 4259.415534978637)
+ Current bracket: (1, 2, 3) (4149.3841336310379, 4108.7083204548444, 4156.7168613952836)
+ Bisect at B = 1 with S = 4149.384133631038
+ Best result: B = 2, S = 4108.708320454844
+ 2 4108.70832045
+ level 1 : rejected replacement (1, 1) -> (1, 1) , dS: 0.0
+ level 1 : rejected insert 1 , dS: 2.30258509299
+ level 0 : rejected replacement (115, 1) -> (115, 1) , dS: 0.0
+ l: 0, N: 115, B: 1
+ l: 1, N: 1, B: 1
+ 4151.68671872
+
+ directed: True overlap: False layered: True deg-corr: True
+ Current bracket: (1, 60, 115) (4079.1051067893313, 4596.3061341987523, 4808.8764024295706)
+ Current bracket: (1, 26, 60) (4079.1051067893313, 4496.5820872632921, 4596.3061341987523)
+ Current bracket: (1, 13, 26) (4079.1051067893313, 4370.6873281497483, 4496.5820872632921)
+ Current bracket: (1, 8, 13) (4079.1051067893313, 4273.0526544098466, 4370.6873281497483)
+ Current bracket: (1, 5, 8) (4079.1051067893313, 4185.3762872671505, 4273.0526544098466)
+ Current bracket: (1, 3, 5) (4079.1051067893313, 4116.5895360878512, 4185.3762872671505)
+ Current bracket: (1, 2, 3) (4079.1051067893313, 4113.7990467107265, 4116.5895360878512)
+ Bisect at B = 1 with S = 4079.105106789331
+ Best result: B = 1, S = 4079.105106789331
+ 1 4079.10510679
+ level 1 : rejected replacement (1, 1) -> (1, 1) , dS: 0.0
+ level 1 : rejected insert 1 , dS: 2.30258509299
+ level 0 : rejected replacement (115, 1) -> (115, 1) , dS: 0.0
+ l: 0, N: 115, B: 1
+ l: 1, N: 1, B: 1
+ 4081.40769188
+
+ directed: True overlap: True layered: False deg-corr: False
+ Current bracket: (1, 60, 115) (2495.8290836444471, 3243.3591987389864, 3708.4144972888325)
+ Current bracket: (1, 26, 60) (2495.8290836444471, 2673.966224376918, 3243.3591987389864)
+ Current bracket: (1, 13, 26) (2495.8290836444471, 2441.2363917608513, 2673.966224376918)
+ Current bracket: (1, 13, 26) (2495.8290836444471, 2441.2363917608513, 2673.966224376918)
+ Bisect at B = 18 with S = 2510.597188861897
+ Current bracket: (1, 13, 18) (2495.8290836444471, 2441.2363917608513, 2510.5971888618969)
+ Bisect at B = 8 with S = 2337.458764563424
+ Current bracket: (1, 8, 13) (2495.8290836444471, 2337.4587645634238, 2441.2363917608513)
+ Bisect at B = 5 with S = 2301.092707087893
+ Current bracket: (1, 5, 8) (2495.8290836444471, 2301.0927070878934, 2337.4587645634238)
+ Bisect at B = 3 with S = 2357.912801442382
+ Current bracket: (3, 5, 8) (2357.9128014423818, 2301.0927070878934, 2337.4587645634238)
+ Bisect at B = 6 with S = 2309.754290101913
+ Current bracket: (3, 5, 6) (2357.9128014423818, 2301.0927070878934, 2309.7542901019133)
+ Bisect at B = 4 with S = 2298.969652099869
+ Best result: B = 4, S = 2298.969652099869
+ 4 2298.9696521
+ level 1 : rejected replacement (1, 1) -> (1, 1) , dS: 0.0
+ level 1 : rejected insert 1 , dS: 0.0
+ level 0 : replaced (115, 1) -> (115, 4) , dS: -167.727455603 2
+ level 1 : rejected replacement (4, 1) -> (4, 1) , dS: 0.0
+ level 1 : rejected insert 4 , dS: 6.73340189184
+ level 0 : skipping 4
+ l: 0, N: 115, B: 4
+ l: 1, N: 4, B: 1
+ 2328.10162804
+
+ directed: True overlap: True layered: False deg-corr: True
+ Current bracket: (1, 60, 115) (2318.8696624551112, 3614.0932889394471, 3337.5708321100401)
+ Current bracket: (1, 26, 60) (2318.8696624551112, 3110.1951905894075, 3614.0932889394471)
+ Current bracket: (1, 13, 26) (2318.8696624551112, 2710.2613205743455, 3110.1951905894075)
+ Current bracket: (1, 8, 13) (2318.8696624551112, 2528.3426363372578, 2710.2613205743455)
+ Current bracket: (1, 5, 8) (2318.8696624551112, 2440.4089835968939, 2528.3426363372578)
+ Current bracket: (1, 3, 5) (2318.8696624551112, 2353.166621031437, 2440.4089835968939)
+ Current bracket: (1, 2, 3) (2318.8696624551112, 2264.6889302483723, 2353.166621031437)
+ Bisect at B = 1 with S = 2318.869662455111
+ Best result: B = 2, S = 2264.688930248372
+ 2 2264.68893025
+ level 1 : rejected replacement (1, 1) -> (1, 1) , dS: 0.0
+ level 1 : rejected insert 1 , dS: 0.0
+ level 0 : replaced (115, 1) -> (115, 2) , dS: -55.0106699939 2
+ level 1 : rejected replacement (2, 1) -> (2, 1) , dS: 0.0
+ level 1 : rejected insert 2 , dS: 1.79175946923
+ level 0 : skipping 2
+ l: 0, N: 115, B: 2
+ l: 1, N: 2, B: 1
+ 2263.85899246
+
+ directed: True overlap: True layered: covariates deg-corr: False
+ Current bracket: (1, 60, 115) (3876.323037275662, 4795.4571396071951, 5076.3584970855154)
+ Current bracket: (1, 26, 60) (3876.323037275662, 4480.189057603242, 4795.4571396071951)
+ Current bracket: (1, 13, 26) (3876.323037275662, 4232.1382878497698, 4480.189057603242)
+ Current bracket: (1, 8, 13) (3876.323037275662, 4069.039478169384, 4232.1382878497698)
+ Current bracket: (1, 5, 8) (3876.323037275662, 3951.8135764459576, 4069.039478169384)
+ Current bracket: (1, 3, 5) (3876.323037275662, 3878.0269892829961, 3951.8135764459576)
+ Current bracket: (1, 2, 3) (3876.323037275662, 3867.7472612920978, 3878.0269892829961)
+ Bisect at B = 1 with S = 3876.323037275662
+ Best result: B = 2, S = 3867.747261292098
+ 2 3867.74726129
+ level 1 : rejected replacement (1, 1) -> (1, 1) , dS: 0.0
+ level 1 : rejected insert 1 , dS: 0.0
+ level 0 : replaced (115, 1) -> (115, 5) , dS: -178.717049511 2
+ level 1 : rejected replacement (5, 1) -> (5, 1) , dS: 0.0
+ level 1 : rejected insert 5 , dS: 9.62377364973
+ level 0 : skipping 5
+ l: 0, N: 115, B: 5
+ l: 1, N: 5, B: 1
+ 3697.60598777
+
+ directed: True overlap: True layered: covariates deg-corr: True
+ Current bracket: (1, 60, 115) (3699.3636160863266, 5167.062731660124, 4705.514831906723)
+ Current bracket: (1, 26, 60) (3699.3636160863266, 4845.8008598492379, 5167.062731660124)
+ Current bracket: (1, 13, 26) (3699.3636160863266, 4614.9766720583375, 4845.8008598492379)
+ Current bracket: (1, 8, 13) (3699.3636160863266, 4368.643894604631, 4614.9766720583375)
+ Current bracket: (1, 5, 8) (3699.3636160863266, 4154.7195000910806, 4368.643894604631)
+ Current bracket: (1, 3, 5) (3699.3636160863266, 3929.3119299306791, 4154.7195000910806)
+ Current bracket: (1, 2, 3) (3699.3636160863266, 3780.6025531339842, 3929.3119299306791)
+ Bisect at B = 1 with S = 3699.363616086327
+ Best result: B = 1, S = 3699.363616086327
+ 1 3699.36361609
+ level 1 : rejected replacement (1, 1) -> (1, 1) , dS: 0.0
+ level 1 : rejected insert 1 , dS: 0.0
+ level 0 : replaced (115, 1) -> (115, 5) , dS: -135.304469399 2
+ level 1 : rejected replacement (5, 1) -> (5, 1) , dS: 0.0
+ level 1 : rejected insert 5 , dS: 9.62377364973
+ level 0 : skipping 5
+ l: 0, N: 115, B: 5
+ l: 1, N: 5, B: 1
+ 3564.05914669
+
+ directed: True overlap: True layered: True deg-corr: False
+ Current bracket: (1, 60, 115) (4149.3841336310379, 5634.8056324677736, 5806.3692226513531)
+ Current bracket: (1, 26, 60) (4149.3841336310379, 5253.8064287341322, 5634.8056324677736)
+ Current bracket: (1, 13, 26) (4149.3841336310379, 4830.7710230477469, 5253.8064287341322)
+ Current bracket: (1, 8, 13) (4149.3841336310379, 4295.682486401598, 4830.7710230477469)
+ Current bracket: (1, 5, 8) (4149.3841336310379, 4052.3861265593323, 4295.682486401598)
+ Current bracket: (1, 5, 8) (4149.3841336310379, 4052.3861265593323, 4295.682486401598)
+ Bisect at B = 3 with S = 3833.118315845553
+ Current bracket: (1, 3, 5) (4149.3841336310379, 3833.1183158455533, 4052.3861265593323)
+ Bisect at B = 2 with S = 4039.690876848615
+ Current bracket: (2, 3, 5) (4039.6908768486151, 3833.1183158455533, 4052.3861265593323)
+ Bisect at B = 4 with S = 4036.591921918258
+ Current bracket: (2, 3, 4) (4039.6908768486151, 3833.1183158455533, 4036.5919219182579)
+ Bisect at B = 2 with S = 4039.690876848615
+ Best result: B = 3, S = 3833.118315845553
+ 3 3833.11831585
+ level 1 : rejected replacement (1, 1) -> (1, 1) , dS: 0.0
+ level 1 : rejected insert 1 , dS: 2.30258509299
+ level 0 : rejected replacement (115, 1) -> (115, 1) , dS: 0.0
+ l: 0, N: 115, B: 1
+ l: 1, N: 1, B: 1
+ 4151.68671872
+
+ directed: True overlap: True layered: True deg-corr: True
+ Current bracket: (1, 60, 115) (4079.1051067893313, 5197.2037808565174, 4808.8764024295706)
+ Current bracket: (1, 26, 60) (4079.1051067893313, 4947.0264093741907, 5197.2037808565174)
+ Current bracket: (1, 13, 26) (4079.1051067893313, 4812.7634310564736, 4947.0264093741907)
+ Current bracket: (1, 8, 13) (4079.1051067893313, 4602.6320859157631, 4812.7634310564736)
+ Current bracket: (1, 5, 8) (4079.1051067893313, 4252.8246786173822, 4602.6320859157631)
+ Current bracket: (1, 3, 5) (4079.1051067893313, 4049.5683588147385, 4252.8246786173822)
+ Current bracket: (1, 3, 5) (4079.1051067893313, 4049.5683588147385, 4252.8246786173822)
+ Bisect at B = 2 with S = 4074.521377773606
+ Current bracket: (2, 3, 5) (4074.5213777736058, 4049.5683588147385, 4252.8246786173822)
+ Bisect at B = 4 with S = 4118.559112781375
+ Current bracket: (2, 3, 4) (4074.5213777736058, 4049.5683588147385, 4118.559112781375)
+ Bisect at B = 2 with S = 4074.521377773606
+ Best result: B = 3, S = 4049.568358814739
+ 3 4049.56835881
+ level 1 : rejected replacement (1, 1) -> (1, 1) , dS: 0.0
+ level 1 : rejected insert 1 , dS: 2.30258509299
+ level 0 : rejected replacement (115, 1) -> (115, 1) , dS: 0.0
+ l: 0, N: 115, B: 1
+ l: 1, N: 1, B: 1
+ 4081.40769188
+
+ directed: False overlap: False layered: False deg-corr: False
+ Current bracket: (1, 60, 115) (2070.9298619612, 2742.0286346974412, 3302.1523929668851)
+ Current bracket: (1, 26, 60) (2070.9298619612, 2163.2011864326296, 2742.0286346974412)
+ Current bracket: (1, 13, 26) (2070.9298619612, 1884.6261937918878, 2163.2011864326296)
+ Current bracket: (1, 13, 26) (2070.9298619612, 1884.6261937918878, 2163.2011864326296)
+ Bisect at B = 18 with S = 1991.644976112192
+ Current bracket: (1, 13, 18) (2070.9298619612, 1884.6261937918878, 1991.6449761121924)
+ Bisect at B = 8 with S = 1824.47791693959
+ Current bracket: (1, 8, 13) (2070.9298619612, 1824.4779169395899, 1884.6261937918878)
+ Bisect at B = 5 with S = 1832.933393330268
+ Current bracket: (5, 8, 13) (1832.933393330268, 1824.4779169395899, 1884.6261937918878)
+ Bisect at B = 10 with S = 1833.549647859825
+ Current bracket: (5, 8, 10) (1832.933393330268, 1824.4779169395899, 1833.5496478598247)
+ Bisect at B = 6 with S = 1824.864187113754
+ Current bracket: (6, 8, 10) (1824.8641871137543, 1824.4779169395899, 1833.5496478598247)
+ Bisect at B = 7 with S = 1821.898539100332
+ Current bracket: (6, 7, 8) (1824.8641871137543, 1821.8985391003318, 1824.4779169395899)
+ Bisect at B = 6 with S = 1824.864187113754
+ Best result: B = 7, S = 1821.898539100332
+ 7 1821.8985391
+ level 1 : rejected replacement (1, 1) -> (1, 1) , dS: 0.0
+ level 1 : rejected insert 1 , dS: 0.0
+ level 0 : replaced (115, 1) -> (115, 10) , dS: -247.539097789 2
+ level 1 : replaced (10, 1) -> (10, 2) , dS: -8.57441720825 2
+ level 2 : rejected replacement (2, 1) -> (2, 1) , dS: 0.0
+ level 2 : rejected insert 2 , dS: 1.79175946923
+ level 1 : skipping 2
+ level 0 : rejected replacement (115, 10) -> (115, 9) , dS: 1.04063514461
+ l: 0, N: 115, B: 10
+ l: 1, N: 10, B: 2
+ l: 2, N: 2, B: 1
+ 1814.81634696
+
+ directed: False overlap: False layered: False deg-corr: True
+ Current bracket: (1, 60, 115) (2039.438415802616, 2687.4979970801901, 3059.7072673586936)
+ Current bracket: (1, 26, 60) (2039.438415802616, 2210.1885588389487, 2687.4979970801901)
+ Current bracket: (1, 13, 26) (2039.438415802616, 1956.4109872858012, 2210.1885588389487)
+ Current bracket: (1, 13, 26) (2039.438415802616, 1956.4109872858012, 2210.1885588389487)
+ Bisect at B = 18 with S = 2056.248563407142
+ Current bracket: (1, 13, 18) (2039.438415802616, 1956.4109872858012, 2056.2485634071418)
+ Bisect at B = 8 with S = 1887.564759326295
+ Current bracket: (1, 8, 13) (2039.438415802616, 1887.5647593262947, 1956.4109872858012)
+ Bisect at B = 5 with S = 1878.123470790204
+ Current bracket: (1, 5, 8) (2039.438415802616, 1878.1234707902045, 1887.5647593262947)
+ Bisect at B = 3 with S = 1900.997091163706
+ Current bracket: (3, 5, 8) (1900.9970911637056, 1878.1234707902045, 1887.5647593262947)
+ Bisect at B = 6 with S = 1873.870847992987
+ Current bracket: (5, 6, 8) (1878.1234707902045, 1873.8708479929869, 1887.5647593262947)
+ Bisect at B = 7 with S = 1878.609827955009
+ Current bracket: (5, 6, 7) (1878.1234707902045, 1873.8708479929869, 1878.6098279550095)
+ Bisect at B = 5 with S = 1878.123470790204
+ Best result: B = 6, S = 1873.870847992987
+ 6 1873.87084799
+ level 1 : rejected replacement (1, 1) -> (1, 1) , dS: 0.0
+ level 1 : rejected insert 1 , dS: 0.0
+ level 0 : replaced (115, 1) -> (115, 5) , dS: -164.055568622 2
+ level 1 : rejected replacement (5, 1) -> (5, 1) , dS: 0.0
+ level 1 : rejected insert 5 , dS: 9.62377364973
+ level 0 : skipping 5
+ l: 0, N: 115, B: 5
+ l: 1, N: 5, B: 1
+ 1875.38284718
+
+ directed: False overlap: False layered: covariates deg-corr: False
+ Current bracket: (1, 60, 115) (3451.4238155924145, 4295.9957091835586, 4658.1574421850237)
+ Current bracket: (1, 26, 60) (3451.4238155924145, 3824.5164704145741, 4295.9957091835586)
+ Current bracket: (1, 13, 26) (3451.4238155924145, 3481.1896063728163, 3824.5164704145741)
+ Current bracket: (1, 8, 13) (3451.4238155924145, 3350.3690166608876, 3481.1896063728163)
+ Current bracket: (1, 8, 13) (3451.4238155924145, 3350.3690166608876, 3481.1896063728163)
+ Bisect at B = 5 with S = 3305.96690163836
+ Current bracket: (1, 5, 8) (3451.4238155924145, 3305.9669016383605, 3350.3690166608876)
+ Bisect at B = 3 with S = 3305.958349260824
+ Current bracket: (1, 3, 5) (3451.4238155924145, 3305.958349260824, 3305.9669016383605)
+ Bisect at B = 2 with S = 3344.118688610963
+ Current bracket: (2, 3, 5) (3344.1186886109631, 3305.958349260824, 3305.9669016383605)
+ Bisect at B = 4 with S = 3290.938676531715
+ Current bracket: (3, 4, 5) (3305.958349260824, 3290.9386765317154, 3305.9669016383605)
+ Bisect at B = 3 with S = 3305.958349260824
+ Best result: B = 4, S = 3290.938676531715
+ 4 3290.93867653
+ level 1 : rejected replacement (1, 1) -> (1, 1) , dS: 0.0
+ level 1 : rejected insert 1 , dS: 0.0
+ level 0 : replaced (115, 1) -> (115, 9) , dS: -236.856154187 2
+ level 1 : rejected replacement (9, 1) -> (9, 1) , dS: 0.0
+ level 1 : rejected insert 9 , dS: 22.9004705474
+ level 0 : skipping 9
+ l: 0, N: 115, B: 9
+ l: 1, N: 9, B: 1
+ 3214.56766141
+
+ directed: False overlap: False layered: covariates deg-corr: True
+ Current bracket: (1, 60, 115) (3419.9323694338309, 4223.9918797736118, 4415.7123165768317)
+ Current bracket: (1, 26, 60) (3419.9323694338309, 3875.1607535720391, 4223.9918797736118)
+ Current bracket: (1, 13, 26) (3419.9323694338309, 3553.4454991243847, 3875.1607535720391)
+ Current bracket: (1, 8, 13) (3419.9323694338309, 3406.1491969341596, 3553.4454991243847)
+ Current bracket: (1, 8, 13) (3419.9323694338309, 3406.1491969341596, 3553.4454991243847)
+ Bisect at B = 5 with S = 3330.744584199459
+ Current bracket: (1, 5, 8) (3419.9323694338309, 3330.7445841994586, 3406.1491969341596)
+ Bisect at B = 3 with S = 3317.96165911753
+ Current bracket: (1, 3, 5) (3419.9323694338309, 3317.9616591175295, 3330.7445841994586)
+ Bisect at B = 2 with S = 3338.6229117634
+ Current bracket: (2, 3, 5) (3338.6229117633998, 3317.9616591175295, 3330.7445841994586)
+ Bisect at B = 4 with S = 3318.361316320577
+ Current bracket: (2, 3, 4) (3338.6229117633998, 3317.9616591175295, 3318.3613163205769)
+ Bisect at B = 2 with S = 3338.6229117634
+ Best result: B = 3, S = 3317.96165911753
+ 3 3317.96165912
+ level 1 : rejected replacement (1, 1) -> (1, 1) , dS: 0.0
+ level 1 : rejected insert 1 , dS: 0.0
+ level 0 : replaced (115, 1) -> (115, 6) , dS: -152.814489428 2
+ level 1 : rejected replacement (6, 1) -> (6, 1) , dS: 0.0
+ level 1 : rejected insert 6 , dS: 12.7148161031
+ level 0 : skipping 6
+ l: 0, N: 115, B: 6
+ l: 1, N: 6, B: 1
+ 3267.11788001
+
+ directed: False overlap: False layered: True deg-corr: False
+ Current bracket: (1, 60, 115) (3724.4849119477913, 4846.7272154433076, 5388.1681677508614)
+ Current bracket: (1, 26, 60) (3724.4849119477913, 4415.9298484742922, 4846.7272154433076)
+ Current bracket: (1, 13, 26) (3724.4849119477913, 4043.547617400895, 4415.9298484742922)
+ Current bracket: (1, 8, 13) (3724.4849119477913, 3831.4149302559326, 4043.547617400895)
+ Current bracket: (1, 5, 8) (3724.4849119477913, 3716.0144978844455, 3831.4149302559326)
+ Current bracket: (1, 5, 8) (3724.4849119477913, 3716.0144978844455, 3831.4149302559326)
+ Bisect at B = 3 with S = 3664.900838079229
+ Current bracket: (1, 3, 5) (3724.4849119477913, 3664.9008380792288, 3716.0144978844455)
+ Bisect at B = 2 with S = 3657.203439841218
+ Current bracket: (1, 2, 3) (3724.4849119477913, 3657.2034398412184, 3664.9008380792288)
+ Bisect at B = 1 with S = 3724.484911947791
+ Best result: B = 2, S = 3657.203439841218
+ 2 3657.20343984
+ level 1 : rejected replacement (1, 1) -> (1, 1) , dS: 0.0
+ level 1 : rejected insert 1 , dS: 2.30258509299
+ level 0 : replaced (115, 1) -> (115, 2) , dS: -52.0783689941 2
+ level 1 : rejected replacement (2, 1) -> (2, 1) , dS: 0.0
+ level 1 : rejected insert 2 , dS: 5.79909265446
+ level 0 : skipping 2
+ l: 0, N: 115, B: 2
+ l: 1, N: 2, B: 1
+ 3674.70912805
+
+ directed: False overlap: False layered: True deg-corr: True
+ Current bracket: (1, 60, 115) (3690.8748461232653, 4390.7235884784623, 4494.4233125699411)
+ Current bracket: (1, 26, 60) (3690.8748461232653, 4212.4807663850643, 4390.7235884784623)
+ Current bracket: (1, 13, 26) (3690.8748461232653, 4029.1609658456218, 4212.4807663850643)
+ Current bracket: (1, 8, 13) (3690.8748461232653, 3913.6020693472092, 4029.1609658456218)
+ Current bracket: (1, 5, 8) (3690.8748461232653, 3834.8957858009617, 3913.6020693472092)
+ Current bracket: (1, 3, 5) (3690.8748461232653, 3727.2813995894244, 3834.8957858009617)
+ Current bracket: (1, 2, 3) (3690.8748461232653, 3690.288221840598, 3727.2813995894244)
+ Bisect at B = 1 with S = 3690.874846123265
+ Best result: B = 2, S = 3690.288221840598
+ 2 3690.28822184
+ level 1 : rejected replacement (1, 1) -> (1, 1) , dS: 0.0
+ level 1 : rejected insert 1 , dS: 2.30258509299
+ level 0 : rejected replacement (115, 1) -> (115, 1) , dS: 0.0
+ l: 0, N: 115, B: 1
+ l: 1, N: 1, B: 1
+ 3693.17743122
+
+ directed: False overlap: True layered: False deg-corr: False
+ Current bracket: (1, 60, 115) (2070.9298619612, 2773.8103951391176, 3302.1523929668847)
+ Current bracket: (1, 26, 60) (2070.9298619612, 2197.5369172261844, 2773.8103951391176)
+ Current bracket: (1, 13, 26) (2070.9298619612, 1888.693285109395, 2197.5369172261844)
+ Current bracket: (1, 13, 26) (2070.9298619612, 1888.693285109395, 2197.5369172261844)
+ Bisect at B = 18 with S = 2008.358125927789
+ Current bracket: (1, 13, 18) (2070.9298619612, 1888.693285109395, 2008.3581259277889)
+ Bisect at B = 8 with S = 1821.812463004034
+ Current bracket: (1, 8, 13) (2070.9298619612, 1821.8124630040336, 1888.693285109395)
+ Bisect at B = 5 with S = 1853.367979967209
+ Current bracket: (5, 8, 13) (1853.3679799672091, 1821.8124630040336, 1888.693285109395)
+ Bisect at B = 10 with S = 1823.97846127917
+ Current bracket: (5, 8, 10) (1853.3679799672091, 1821.8124630040336, 1823.9784612791696)
+ Bisect at B = 6 with S = 1828.525381763233
+ Current bracket: (6, 8, 10) (1828.5253817632329, 1821.8124630040336, 1823.9784612791696)
+ Bisect at B = 7 with S = 1823.245540811884
+ Current bracket: (7, 8, 10) (1823.2455408118842, 1821.8124630040336, 1823.9784612791696)
+ Bisect at B = 9 with S = 1822.086944968345
+ Current bracket: (7, 8, 9) (1823.2455408118842, 1821.8124630040336, 1822.0869449683451)
+ Bisect at B = 7 with S = 1823.245540811884
+ Best result: B = 8, S = 1821.812463004034
+ 8 1821.812463
+ level 1 : rejected replacement (1, 1) -> (1, 1) , dS: 0.0
+ level 1 : rejected insert 1 , dS: 0.0
+ level 0 : replaced (115, 1) -> (115, 8) , dS: -232.661496277 2
+ level 1 : replaced (8, 1) -> (8, 2) , dS: -2.95970180508 2
+ level 2 : rejected replacement (2, 1) -> (2, 1) , dS: 0.0
+ level 2 : rejected insert 2 , dS: 1.79175946923
+ level 1 : skipping 2
+ level 0 : replaced (115, 8) -> (115, 8) , dS: -4.93282634306 3
+ level 1 : rejected replacement (8, 2) -> (8, 2) , dS: 0.0
+ level 1 : rejected insert 8 , dS: 19.3741100228
+ level 0 : skipping 8
+ l: 0, N: 115, B: 8
+ l: 1, N: 8, B: 2
+ l: 2, N: 2, B: 1
+ 1830.37583754
+
+ directed: False overlap: True layered: False deg-corr: True
+ Current bracket: (1, 60, 115) (2039.438415802616, 2791.218655464937, 3059.7072673586931)
+ Current bracket: (1, 26, 60) (2039.438415802616, 2596.1318468202285, 2791.218655464937)
+ Current bracket: (1, 13, 26) (2039.438415802616, 2249.7395717949853, 2596.1318468202285)
+ Current bracket: (1, 8, 13) (2039.438415802616, 2192.5567166861247, 2249.7395717949853)
+ Current bracket: (1, 5, 8) (2039.438415802616, 2155.8270672199023, 2192.5567166861247)
+ Current bracket: (1, 3, 5) (2039.438415802616, 2097.064562904091, 2155.8270672199023)
+ Current bracket: (1, 2, 3) (2039.438415802616, 2067.0267866042686, 2097.064562904091)
+ Bisect at B = 1 with S = 2039.438415802616
+ Best result: B = 1, S = 2039.438415802616
+ 1 2039.4384158
+ level 1 : rejected replacement (1, 1) -> (1, 1) , dS: 0.0
+ level 1 : rejected insert 1 , dS: 0.0
+ level 0 : rejected replacement (115, 1) -> (115, 1) , dS: 0.0
+ l: 0, N: 115, B: 1
+ l: 1, N: 1, B: 1
+ 2039.4384158
+
+ directed: False overlap: True layered: covariates deg-corr: False
+ Current bracket: (1, 60, 115) (3451.4238155924145, 4331.561281582568, 4658.1574421850237)
+ Current bracket: (1, 26, 60) (3451.4238155924145, 3901.5868258047312, 4331.561281582568)
+ Current bracket: (1, 13, 26) (3451.4238155924145, 3673.3309590473609, 3901.5868258047312)
+ Current bracket: (1, 8, 13) (3451.4238155924145, 3552.8365768937738, 3673.3309590473609)
+ Current bracket: (1, 5, 8) (3451.4238155924145, 3445.7715685052244, 3552.8365768937738)
+ Current bracket: (1, 5, 8) (3451.4238155924145, 3445.7715685052244, 3552.8365768937738)
+ Bisect at B = 3 with S = 3378.659618732226
+ Current bracket: (1, 3, 5) (3451.4238155924145, 3378.6596187322261, 3445.7715685052244)
+ Bisect at B = 2 with S = 3384.190161466892
+ Current bracket: (2, 3, 5) (3384.1901614668918, 3378.6596187322261, 3445.7715685052244)
+ Bisect at B = 4 with S = 3395.991818320718
+ Current bracket: (2, 3, 4) (3384.1901614668918, 3378.6596187322261, 3395.9918183207178)
+ Bisect at B = 2 with S = 3384.190161466892
+ Best result: B = 3, S = 3378.659618732226
+ 3 3378.65961873
+ level 1 : rejected replacement (1, 1) -> (1, 1) , dS: 0.0
+ level 1 : rejected insert 1 , dS: 0.0
+ level 0 : replaced (115, 1) -> (115, 8) , dS: -236.467003238 2
+ level 1 : rejected replacement (8, 1) -> (8, 1) , dS: 0.0
+ level 1 : rejected insert 8 , dS: 19.3741100228
+ level 0 : skipping 8
+ l: 0, N: 115, B: 8
+ l: 1, N: 8, B: 1
+ 3214.95681235
+
+ directed: False overlap: True layered: covariates deg-corr: True
+ Current bracket: (1, 60, 115) (3419.9323694338309, 4273.5270137403832, 4415.7123165768317)
+ Current bracket: (1, 26, 60) (3419.9323694338309, 4003.9207484397484, 4273.5270137403832)
+ Current bracket: (1, 13, 26) (3419.9323694338309, 3747.5119493111124, 4003.9207484397484)
+ Current bracket: (1, 8, 13) (3419.9323694338309, 3587.8678820583082, 3747.5119493111124)
+ Current bracket: (1, 5, 8) (3419.9323694338309, 3527.8285413311705, 3587.8678820583082)
+ Current bracket: (1, 3, 5) (3419.9323694338309, 3450.2450966889314, 3527.8285413311705)
+ Current bracket: (1, 2, 3) (3419.9323694338309, 3388.2681843019941, 3450.2450966889314)
+ Bisect at B = 1 with S = 3419.932369433831
+ Best result: B = 2, S = 3388.268184301994
+ 2 3388.2681843
+ level 1 : rejected replacement (1, 1) -> (1, 1) , dS: 0.0
+ level 1 : rejected insert 1 , dS: 0.0
+ level 0 : replaced (115, 1) -> (115, 6) , dS: -164.980561445 2
+ level 1 : rejected replacement (6, 1) -> (6, 1) , dS: 0.0
+ level 1 : rejected insert 6 , dS: 12.7148161031
+ level 0 : skipping 6
+ l: 0, N: 115, B: 6
+ l: 1, N: 6, B: 1
+ 3254.95180799
+
+ directed: False overlap: True layered: True deg-corr: False
+ Current bracket: (1, 60, 115) (3724.4849119477913, 5222.4917279727715, 5388.1681677508614)
+ Current bracket: (1, 26, 60) (3724.4849119477913, 4745.7356091147667, 5222.4917279727715)
+ Current bracket: (1, 13, 26) (3724.4849119477913, 4150.3055871227125, 4745.7356091147667)
+ Current bracket: (1, 8, 13) (3724.4849119477913, 3778.92601352782, 4150.3055871227125)
+ Current bracket: (1, 5, 8) (3724.4849119477913, 3587.5603537522038, 3778.92601352782)
+ Current bracket: (1, 5, 8) (3724.4849119477913, 3587.5603537522038, 3778.92601352782)
+ Bisect at B = 3 with S = 3529.792099317828
+ Current bracket: (1, 3, 5) (3724.4849119477913, 3529.7920993178282, 3587.5603537522038)
+ Bisect at B = 2 with S = 3545.492577998865
+ Current bracket: (2, 3, 5) (3545.4925779988648, 3529.7920993178282, 3587.5603537522038)
+ Bisect at B = 4 with S = 3552.535413509081
+ Current bracket: (2, 3, 4) (3545.4925779988648, 3529.7920993178282, 3552.5354135090811)
+ Bisect at B = 2 with S = 3545.492577998865
+ Best result: B = 3, S = 3529.792099317828
+ 3 3529.79209932
+ level 1 : rejected replacement (1, 1) -> (1, 1) , dS: 0.0
+ level 1 : rejected insert 1 , dS: 2.30258509299
+ level 0 : replaced (115, 1) -> (115, 2) , dS: -52.0783689941 2
+ level 1 : rejected replacement (2, 1) -> (2, 1) , dS: 0.0
+ level 1 : rejected insert 2 , dS: 5.79909265446
+ level 0 : skipping 2
+ l: 0, N: 115, B: 2
+ l: 1, N: 2, B: 1
+ 3674.70912805
+
+ directed: False overlap: True layered: True deg-corr: True
+ Current bracket: (1, 60, 115) (3690.8748461232653, 4757.8922348797005, 4494.4233125699411)
+ Current bracket: (1, 26, 60) (3690.8748461232653, 4578.68710077166, 4757.8922348797005)
+ Current bracket: (1, 13, 26) (3690.8748461232653, 4249.4783928541656, 4578.68710077166)
+ Current bracket: (1, 8, 13) (3690.8748461232653, 3986.881326217177, 4249.4783928541656)
+ Current bracket: (1, 5, 8) (3690.8748461232653, 3856.2684964836299, 3986.881326217177)
+ Current bracket: (1, 3, 5) (3690.8748461232653, 3699.7810945700962, 3856.2684964836299)
+ Current bracket: (1, 2, 3) (3690.8748461232653, 3641.6685995295234, 3699.7810945700962)
+ Bisect at B = 1 with S = 3690.874846123265
+ Best result: B = 2, S = 3641.668599529523
+ 2 3641.66859953
+ level 1 : rejected replacement (1, 1) -> (1, 1) , dS: 0.0
+ level 1 : rejected insert 1 , dS: 2.30258509299
+ level 0 : rejected replacement (115, 1) -> (115, 1) , dS: 0.0
+ l: 0, N: 115, B: 1
+ l: 1, N: 1, B: 1
+ 3693.17743122
diff --git a/doc/test_inference.py b/doc/test_inference.py
new file mode 100755
index 0000000000000000000000000000000000000000..4371e19e5305de15e455f5a4016e01610d16807e
--- /dev/null
+++ b/doc/test_inference.py
@@ -0,0 +1,141 @@
+#!/bin/env python
+
+from graph_tool.all import *
+import numpy.random
+from numpy.random import randint
+
+seed_rng(42)
+numpy.random.seed(42)
+
+graph_tool.inference.set_test(True)
+
+g = collection.data["football"]
+ec = g.new_ep("int", randint(0, 10, g.num_edges()))
+
+def gen_state(directed, deg_corr, layers, overlap):
+ u = GraphView(g, directed=directed)
+ if layers != False:
+ state = graph_tool.inference.LayeredBlockState(u, B=u.num_vertices(),
+ deg_corr=deg_corr,
+ ec=ec.copy(),
+ overlap=overlap,
+ layers=layers == True)
+ elif overlap:
+ state = graph_tool.inference.OverlapBlockState(u, B=2 * u.num_edges(),
+ deg_corr=deg_corr)
+ else:
+ state = graph_tool.inference.BlockState(u, B=u.num_vertices(),
+ deg_corr=deg_corr)
+ return state
+
+
+for directed in [True, False]:
+ for overlap in [False, True]:
+ for layered in [False, "covariates", True]:
+ for deg_corr in [False, True]:
+ for dl in [False, True]:
+
+ print("\ndirected:", directed, "overlap:", overlap,
+ "layered:", layered, "deg-corr:", deg_corr, "dl:", dl)
+
+
+ print("\t mcmc (unweighted)")
+ state = gen_state(directed, deg_corr, layered, overlap)
+
+ print("\t\t", state.mcmc_sweep(beta=0, allow_empty=True,
+ entropy_args=dict(dl=dl)),
+ (state.wr.a > 0).sum())
+ if overlap:
+ print("\t\t", state.mcmc_sweep(beta=0, bundled=True,
+ allow_empty=True,
+ entropy_args=dict(dl=dl)),
+ (state.wr.a > 0).sum())
+
+ state = gen_state(directed, deg_corr, layered, overlap)
+
+ if not overlap:
+ print("\t mcmc")
+ bstate = state.get_block_state(vweight=True,
+ deg_corr=deg_corr)
+
+ print("\t\t",
+ bstate.mcmc_sweep(beta=0,
+ allow_empty=True,
+ entropy_args=dict(dl=dl,
+ multigraph=False)),
+ (bstate.wr.a > 0).sum())
+
+ print("\t\t",
+ bstate.mcmc_sweep(beta=0, allow_empty=True,
+ entropy_args=dict(dl=dl,
+ multigraph=False)),
+ (bstate.wr.a > 0).sum())
+
+ print("\t\t",
+ bstate.gibbs_sweep(beta=0, allow_empty=True,
+ entropy_args=dict(dl=dl,
+ multigraph=False)),
+ (bstate.wr.a > 0).sum())
+
+ print("\t merge")
+
+ state = gen_state(directed, deg_corr, layered, overlap)
+
+ if not overlap:
+ bstate = state.get_block_state(vweight=True,
+ deg_corr=deg_corr)
+
+ print("\t\t",
+ bstate.merge_sweep(50,
+ entropy_args=dict(dl=dl,
+ multigraph=False)))
+
+ bstate = bstate.copy()
+
+ print("\t\t",
+ bstate.mcmc_sweep(beta=0, allow_empty=True,
+ entropy_args=dict(dl=dl,
+ multigraph=False)))
+ print("\t\t",
+ bstate.gibbs_sweep(beta=0, allow_empty=True,
+ entropy_args=dict(dl=dl,
+ multigraph=False)))
+ else:
+ print("\t\t",
+ state.merge_sweep(50,
+ entropy_args=dict(dl=dl,
+ multigraph=False)))
+
+ print("\t shrink")
+
+ state = gen_state(directed, deg_corr, layered, overlap)
+ state = state.shrink(B=5, entropy_args=dict(dl=dl,
+ multigraph=False))
+ print("\t\t", state.B)
+
+for directed in [True, False]:
+ for overlap in [False, True]:
+ for layered in [False, "covariates", True]:
+ for deg_corr in [False, True]:
+ print("\ndirected:", directed, "overlap:", overlap,
+ "layered:", layered, "deg-corr:", deg_corr)
+
+ state = minimize_blockmodel_dl(GraphView(g, directed=directed),
+ verbose=(1, "\t"),
+ deg_corr=deg_corr,
+ overlap=overlap,
+ layers=layered != False,
+ state_args=dict(ec=ec,
+ layers=(layered == True)))
+ print(state.B, state.entropy())
+
+ state = minimize_nested_blockmodel_dl(GraphView(g, directed=directed),
+ verbose=(1, "\t"),
+ deg_corr=deg_corr,
+ overlap=overlap,
+ layers=layered != False,
+ state_args=dict(ec=ec,
+ layers=(layered == True)))
+ state.print_summary()
+ print(state.entropy())
+
diff --git a/src/boost-workaround/boost/graph/reverse_graph_alt.hpp b/src/boost-workaround/boost/graph/reverse_graph_alt.hpp
index 1bfb8c8108e31b9d6c66a259decc736b022a62e3..a423f06e07970a4559a83b249868b0c75b531fae 100644
--- a/src/boost-workaround/boost/graph/reverse_graph_alt.hpp
+++ b/src/boost-workaround/boost/graph/reverse_graph_alt.hpp
@@ -306,7 +306,8 @@ namespace detail {
typedef typename property_traits::reference reference;
typedef typename property_traits::category category;
- explicit reverse_graph_edge_property_map(const PM& pm): underlying_pm(pm) {}
+ reverse_graph_edge_property_map(const PM& pm): underlying_pm(pm) {}
+ reverse_graph_edge_property_map() = default;
friend reference
get(const reverse_graph_edge_property_map& m,
diff --git a/src/graph/Makefile.am b/src/graph/Makefile.am
index 4aa05097e1960f58400a374d92d7a5c08a470068..1519a4ab06b1abeddfb63c9223c4b2fb5b0964f9 100644
--- a/src/graph/Makefile.am
+++ b/src/graph/Makefile.am
@@ -1,6 +1,6 @@
## Process this file with automake to produce Makefile.in
-SUBDIRS = centrality clustering community correlations draw flow generation layout search spectral stats topology util
+SUBDIRS = centrality clustering community_old correlations draw flow generation inference layout search spectral stats topology util
AM_CPPFLAGS =\
-I$(srcdir)/.. \
diff --git a/src/graph/community/Makefile.am b/src/graph/community_old/Makefile.am
similarity index 69%
rename from src/graph/community/Makefile.am
rename to src/graph/community_old/Makefile.am
index 543f26d7714cc844622f02c02a3e686724cd609f..c9e3b040f50f0769d54cdb23e49affc901769391 100644
--- a/src/graph/community/Makefile.am
+++ b/src/graph/community_old/Makefile.am
@@ -4,11 +4,11 @@ AM_CPPFLAGS = $(MOD_CPPFLAGS)
AM_CFLAGS = $(AM_CXXFLAGS)
-libgraph_tool_communitydir = $(MOD_DIR)/community
+libgraph_tool_communitydir = $(MOD_DIR)/community_old
libgraph_tool_community_LTLIBRARIES = libgraph_tool_community.la
-libgraph_tool_community_la_includedir = $(MOD_DIR)/include/community
+libgraph_tool_community_la_includedir = $(MOD_DIR)/include/community_old
libgraph_tool_community_la_LIBADD = $(MOD_LIBADD)
@@ -19,16 +19,10 @@ libgraph_tool_community_la_SOURCES = \
graph_blockmodel_covariates.cc \
graph_blockmodel_overlap.cc \
graph_community.cc \
- graph_community_network.cc \
- graph_community_network_edges.cc \
- graph_community_network_vavg.cc \
- graph_community_network_eavg.cc \
- graph_community_network_eavg_imp1.cc \
spence.cc
libgraph_tool_community_la_include_HEADERS = \
graph_blockmodel.hh \
graph_blockmodel_covariates.hh \
graph_blockmodel_overlap.hh \
- graph_community.hh \
- graph_community_network.hh
+ graph_community.hh
diff --git a/src/graph/community/graph_blockmodel.cc b/src/graph/community_old/graph_blockmodel.cc
similarity index 95%
rename from src/graph/community/graph_blockmodel.cc
rename to src/graph/community_old/graph_blockmodel.cc
index 6dee2ccf55a0458ebd20619a54063d68f22ddf74..778d26499420449e44171587a892e77755206193 100644
--- a/src/graph/community/graph_blockmodel.cc
+++ b/src/graph/community_old/graph_blockmodel.cc
@@ -58,58 +58,64 @@ using namespace graph_tool;
namespace graph_tool
{
-vector __safelog_cache;
-vector __xlogx_cache;
-vector __lgamma_cache;
-
-void init_safelog(size_t x)
-{
- size_t old_size = __safelog_cache.size();
- if (x >= old_size)
- {
- __safelog_cache.resize(x + 1);
- for (size_t i = old_size; i < __safelog_cache.size(); ++i)
- __safelog_cache[i] = safelog(double(i));
- }
-}
-
-void clear_safelog()
-{
- vector().swap(__safelog_cache);
-}
-
-
-void init_xlogx(size_t x)
-{
- size_t old_size = __xlogx_cache.size();
- if (x >= old_size)
- {
- __xlogx_cache.resize(x + 1);
- for (size_t i = old_size; i < __xlogx_cache.size(); ++i)
- __xlogx_cache[i] = i * safelog(i);
- }
-}
-
-void clear_xlogx()
-{
- vector().swap(__xlogx_cache);
-}
-
-void init_lgamma(size_t x)
-{
- size_t old_size = __lgamma_cache.size();
- if (x >= old_size)
- {
- __lgamma_cache.resize(x + 1);
- for (size_t i = old_size; i < __lgamma_cache.size(); ++i)
- __lgamma_cache[i] = lgamma(i);
- }
-}
-
-void clear_lgamma()
-{
- vector().swap(__lgamma_cache);
-}
+// vector __safelog_cache;
+// vector __xlogx_cache;
+// vector __lgamma_cache;
+
+void init_safelog(size_t x);
+// void init_safelog(size_t x)
+// {
+// size_t old_size = __safelog_cache.size();
+// if (x >= old_size)
+// {
+// __safelog_cache.resize(x + 1);
+// for (size_t i = old_size; i < __safelog_cache.size(); ++i)
+// __safelog_cache[i] = safelog(double(i));
+// }
+// }
+
+void clear_safelog();
+// void clear_safelog()
+// {
+// vector().swap(__safelog_cache);
+// }
+
+void init_xlogx(size_t x);
+
+// void init_xlogx(size_t x)
+// {
+// size_t old_size = __xlogx_cache.size();
+// if (x >= old_size)
+// {
+// __xlogx_cache.resize(x + 1);
+// for (size_t i = old_size; i < __xlogx_cache.size(); ++i)
+// __xlogx_cache[i] = i * safelog(i);
+// }
+// }
+
+void clear_xlogx();
+// void clear_xlogx()
+// {
+// vector().swap(__xlogx_cache);
+// }
+
+void init_lgamma(size_t x);
+// void init_lgamma(size_t x)
+// {
+// size_t old_size = __lgamma_cache.size();
+// if (x >= old_size)
+// {
+// __lgamma_cache.resize(x + 1);
+// for (size_t i = old_size; i < __lgamma_cache.size(); ++i)
+// __lgamma_cache[i] = lgamma(i);
+// }
+// }
+
+void clear_lgamma();
+// void clear_lgamma()
+// {
+// vector().swap(__lgamma_cache);
+// }
}
diff --git a/src/graph/community/graph_blockmodel.hh b/src/graph/community_old/graph_blockmodel.hh
similarity index 100%
rename from src/graph/community/graph_blockmodel.hh
rename to src/graph/community_old/graph_blockmodel.hh
diff --git a/src/graph/community/graph_blockmodel_covariates.cc b/src/graph/community_old/graph_blockmodel_covariates.cc
similarity index 95%
rename from src/graph/community/graph_blockmodel_covariates.cc
rename to src/graph/community_old/graph_blockmodel_covariates.cc
index 382de8fd9b8cfb36c670e91cdcf006f59b3c369d..ad6e6b536f8476d9a28106f9ac13487a0d6a9930 100644
--- a/src/graph/community/graph_blockmodel_covariates.cc
+++ b/src/graph/community_old/graph_blockmodel_covariates.cc
@@ -690,55 +690,55 @@ void do_split_graph(GraphInterface& gi, boost::any& aec, boost::any& ab,
std::ref(uvmap)))();
}
-bool bmap_has(const bmap_t& bmap, size_t c, size_t r)
-{
- if (c > bmap.size())
- throw GraphException("invalid covariate value:" + lexical_cast(c));
- auto iter = bmap[c].find(r);
- if (iter == bmap[c].end())
- return false;
- return true;
-}
+// bool bmap_has(const bmap_t& bmap, size_t c, size_t r)
+// {
+// if (c > bmap.size())
+// throw GraphException("invalid covariate value:" + lexical_cast(c));
+// auto iter = bmap[c].find(r);
+// if (iter == bmap[c].end())
+// return false;
+// return true;
+// }
-size_t bmap_get(const bmap_t& bmap, size_t c, size_t r)
-{
- if (c > bmap.size())
- throw GraphException("invalid covariate value:" + lexical_cast(c));
- auto iter = bmap[c].find(r);
- if (iter == bmap[c].end())
- throw GraphException("no mapping for block " + lexical_cast(r)
- + " in layer " + lexical_cast(c));
- return iter->second;
-}
+// size_t bmap_get(const bmap_t& bmap, size_t c, size_t r)
+// {
+// if (c > bmap.size())
+// throw GraphException("invalid covariate value:" + lexical_cast(c));
+// auto iter = bmap[c].find(r);
+// if (iter == bmap[c].end())
+// throw GraphException("no mapping for block " + lexical_cast(r)
+// + " in layer " + lexical_cast(c));
+// return iter->second;
+// }
-void bmap_set(bmap_t& bmap, size_t c, size_t r, size_t r_u)
-{
- if (c > bmap.size())
- throw GraphException("invalid covariate value:" + lexical_cast(c));
- bmap[c][r] = r_u;
-}
+// void bmap_set(bmap_t& bmap, size_t c, size_t r, size_t r_u)
+// {
+// if (c > bmap.size())
+// throw GraphException("invalid covariate value:" + lexical_cast(c));
+// bmap[c][r] = r_u;
+// }
-void bmap_del_c(bmap_t& bmap, size_t c)
-{
- if (c > bmap.size())
- throw GraphException("invalid covariate value:" + lexical_cast(c));
- bmap.erase(bmap.begin() + c);
-}
+// void bmap_del_c(bmap_t& bmap, size_t c)
+// {
+// if (c > bmap.size())
+// throw GraphException("invalid covariate value:" + lexical_cast(c));
+// bmap.erase(bmap.begin() + c);
+// }
-bmap_t bmap_copy(const bmap_t& bmap)
-{
- return bmap;
-}
+// bmap_t bmap_copy(const bmap_t& bmap)
+// {
+// return bmap;
+// }
void export_blockmodel_covariate()
{
- boost::python::class_("bmap_t")
- .def("has", bmap_has)
- .def("get", bmap_get)
- .def("set", bmap_set)
- .def("del_c", bmap_del_c)
- .def("copy", bmap_copy);
+ // boost::python::class_("bmap_t")
+ // .def("has", bmap_has)
+ // .def("get", bmap_get)
+ // .def("set", bmap_set)
+ // .def("del_c", bmap_del_c)
+ // .def("copy", bmap_copy);
boost::python::def("cov_move_sweep", do_cov_move_sweep);
boost::python::def("covariate_entropy", do_covariate_entropy);
diff --git a/src/graph/community/graph_blockmodel_covariates.hh b/src/graph/community_old/graph_blockmodel_covariates.hh
similarity index 100%
rename from src/graph/community/graph_blockmodel_covariates.hh
rename to src/graph/community_old/graph_blockmodel_covariates.hh
diff --git a/src/graph/community/graph_blockmodel_overlap.cc b/src/graph/community_old/graph_blockmodel_overlap.cc
similarity index 100%
rename from src/graph/community/graph_blockmodel_overlap.cc
rename to src/graph/community_old/graph_blockmodel_overlap.cc
diff --git a/src/graph/community/graph_blockmodel_overlap.hh b/src/graph/community_old/graph_blockmodel_overlap.hh
similarity index 100%
rename from src/graph/community/graph_blockmodel_overlap.hh
rename to src/graph/community_old/graph_blockmodel_overlap.hh
diff --git a/src/graph/community/graph_community.cc b/src/graph/community_old/graph_community.cc
similarity index 76%
rename from src/graph/community/graph_community.cc
rename to src/graph/community_old/graph_community.cc
index 45c7d356da8431e222bc425e82737793a38b08d8..0515d56d30bfd6779fb8c3c1442fe699b77f2767 100644
--- a/src/graph/community/graph_community.cc
+++ b/src/graph/community_old/graph_community.cc
@@ -97,27 +97,6 @@ double modularity(GraphInterface& g, boost::any weight, boost::any property)
using namespace boost::python;
-extern void community_network(GraphInterface& gi, GraphInterface& cgi,
- boost::any community_property,
- boost::any condensed_community_property,
- boost::any vertex_count, boost::any edge_count,
- boost::any vweight, boost::any eweight,
- bool self_loops, bool parallel_edges);
-
-void community_network_vavg(GraphInterface& gi, GraphInterface& cgi,
- boost::any community_property,
- boost::any condensed_community_property,
- boost::any vweight,
- boost::python::list avprops);
-
-void community_network_eavg(GraphInterface& gi, GraphInterface& cgi,
- boost::any community_property,
- boost::any condensed_community_property,
- boost::any eweight,
- boost::python::list aeprops,
- bool self_loops);
-
-
extern void export_blockmodel();
extern void export_blockmodel_overlap();
extern void export_blockmodel_covariate();
@@ -126,9 +105,6 @@ BOOST_PYTHON_MODULE(libgraph_tool_community)
{
def("community_structure", &community_structure);
def("modularity", &modularity);
- def("community_network", &community_network);
- def("community_network_vavg", &community_network_vavg);
- def("community_network_eavg", &community_network_eavg);
export_blockmodel();
export_blockmodel_overlap();
diff --git a/src/graph/community/graph_community.hh b/src/graph/community_old/graph_community.hh
similarity index 100%
rename from src/graph/community/graph_community.hh
rename to src/graph/community_old/graph_community.hh
diff --git a/src/graph/community/spence.cc b/src/graph/community_old/spence.cc
similarity index 100%
rename from src/graph/community/spence.cc
rename to src/graph/community_old/spence.cc
diff --git a/src/graph/draw/graph_cairo_draw.cc b/src/graph/draw/graph_cairo_draw.cc
index 7fd13ee2e091917840b99821bb8b6fff92da08a7..c2fe4e0570837e37ac8287b21cd9e809391194fd 100644
--- a/src/graph/draw/graph_cairo_draw.cc
+++ b/src/graph/draw/graph_cairo_draw.cc
@@ -1045,7 +1045,7 @@ public:
_attrs.template get >(EDGE_CONTROL_POINTS);
vector gradient =
_attrs.template get >(EDGE_GRADIENT);
- if (gradient.size() == 2)
+ if (gradient.size() == 1)
{
auto e_color = _attrs.template get(EDGE_COLOR);
auto s_color = _s._attrs.template get(VERTEX_FILL_COLOR);
diff --git a/src/graph/generation/Makefile.am b/src/graph/generation/Makefile.am
index 4cf6e379a9ad67fe3309cbfdf68feb7b6e98b9af..e31ad435bce509e2fd1621dd2dc8f52363b21a50 100644
--- a/src/graph/generation/Makefile.am
+++ b/src/graph/generation/Makefile.am
@@ -15,29 +15,35 @@ libgraph_tool_generation_la_LIBADD = $(MOD_LIBADD) $(CGAL_LIBADD)
libgraph_tool_generation_la_LDFLAGS = $(MOD_LDFLAGS)
libgraph_tool_generation_la_SOURCES = \
+ graph_community_network.cc \
+ graph_community_network_eavg.cc \
+ graph_community_network_eavg_imp1.cc \
+ graph_community_network_edges.cc \
+ graph_community_network_vavg.cc \
+ graph_complete.cc \
graph_generation.cc \
- graph_rewiring.cc \
- graph_predecessor.cc \
+ graph_geometric.cc \
+ graph_lattice.cc \
graph_line_graph.cc \
+ graph_predecessor.cc \
+ graph_price.cc \
+ graph_rewiring.cc \
+ graph_triangulation.cc \
graph_union.cc \
- graph_union_vprop.cc \
graph_union_eprop.cc \
- graph_triangulation.cc \
- graph_lattice.cc \
- graph_geometric.cc \
- graph_complete.cc \
- graph_price.cc
+ graph_union_vprop.cc
libgraph_tool_generation_la_include_HEADERS = \
+ dynamic_sampler.hh \
+ graph_community_network.hh \
+ graph_complete.hh \
graph_generation.hh \
- graph_rewiring.hh \
- graph_predecessor.hh \
- graph_union.hh \
- graph_triangulation.hh \
- graph_lattice.hh \
graph_geometric.hh \
- graph_complete.hh \
+ graph_lattice.hh \
+ graph_predecessor.hh \
graph_price.hh \
- dynamic_sampler.hh \
+ graph_rewiring.hh \
+ graph_triangulation.hh \
+ graph_union.hh \
sampler.hh
diff --git a/src/graph/community/graph_community_network.cc b/src/graph/generation/graph_community_network.cc
similarity index 100%
rename from src/graph/community/graph_community_network.cc
rename to src/graph/generation/graph_community_network.cc
diff --git a/src/graph/community/graph_community_network.hh b/src/graph/generation/graph_community_network.hh
similarity index 100%
rename from src/graph/community/graph_community_network.hh
rename to src/graph/generation/graph_community_network.hh
diff --git a/src/graph/community/graph_community_network_eavg.cc b/src/graph/generation/graph_community_network_eavg.cc
similarity index 100%
rename from src/graph/community/graph_community_network_eavg.cc
rename to src/graph/generation/graph_community_network_eavg.cc
diff --git a/src/graph/community/graph_community_network_eavg_imp1.cc b/src/graph/generation/graph_community_network_eavg_imp1.cc
similarity index 100%
rename from src/graph/community/graph_community_network_eavg_imp1.cc
rename to src/graph/generation/graph_community_network_eavg_imp1.cc
diff --git a/src/graph/community/graph_community_network_edges.cc b/src/graph/generation/graph_community_network_edges.cc
similarity index 100%
rename from src/graph/community/graph_community_network_edges.cc
rename to src/graph/generation/graph_community_network_edges.cc
diff --git a/src/graph/community/graph_community_network_vavg.cc b/src/graph/generation/graph_community_network_vavg.cc
similarity index 100%
rename from src/graph/community/graph_community_network_vavg.cc
rename to src/graph/generation/graph_community_network_vavg.cc
diff --git a/src/graph/generation/graph_generation.cc b/src/graph/generation/graph_generation.cc
index 8399350ef4fd5708bc8da8bacb264ac538d20dff..82dbf05591c2292380b5caa361c79e28d5f884df 100644
--- a/src/graph/generation/graph_generation.cc
+++ b/src/graph/generation/graph_generation.cc
@@ -48,9 +48,10 @@ private:
boost::python::object _o;
};
-void generate_graph(GraphInterface& gi, size_t N, boost::python::object deg_sample,
- bool no_parallel, bool no_self_loops, bool undirected,
- rng_t& rng, bool verbose, bool verify)
+void generate_graph(GraphInterface& gi, size_t N,
+ boost::python::object deg_sample, bool no_parallel,
+ bool no_self_loops, bool undirected, rng_t& rng,
+ bool verbose, bool verify)
{
typedef graph_tool::detail::get_all_graph_views::apply<
graph_tool::detail::filt_scalar_type, boost::mpl::bool_,
@@ -84,15 +85,34 @@ void vertex_property_union(GraphInterface& ugi, GraphInterface& gi,
void edge_property_union(GraphInterface& ugi, GraphInterface& gi,
boost::any p_vprop, boost::any p_eprop,
boost::any uprop, boost::any prop);
-void triangulation(GraphInterface& gi, boost::python::object points, boost::any pos,
- string type, bool periodic);
+void triangulation(GraphInterface& gi, boost::python::object points,
+ boost::any pos, string type, bool periodic);
void lattice(GraphInterface& gi, boost::python::object oshape, bool periodic);
void geometric(GraphInterface& gi, boost::python::object opoints, double r,
boost::python::object orange, bool periodic, boost::any pos);
void price(GraphInterface& gi, size_t N, double gamma, double c, size_t m,
rng_t& rng);
void complete(GraphInterface& gi, size_t N, bool directed, bool self_loops);
-void circular(GraphInterface& gi, size_t N, size_t k, bool directed, bool self_loops);
+void circular(GraphInterface& gi, size_t N, size_t k, bool directed,
+ bool self_loops);
+
+void community_network(GraphInterface& gi, GraphInterface& cgi,
+ boost::any community_property,
+ boost::any condensed_community_property,
+ boost::any vertex_count, boost::any edge_count,
+ boost::any vweight, boost::any eweight, bool self_loops,
+ bool parallel_edges);
+
+void community_network_vavg(GraphInterface& gi, GraphInterface& cgi,
+ boost::any community_property,
+ boost::any condensed_community_property,
+ boost::any vweight, boost::python::list avprops);
+
+void community_network_eavg(GraphInterface& gi, GraphInterface& cgi,
+ boost::any community_property,
+ boost::any condensed_community_property,
+ boost::any eweight, boost::python::list aeprops,
+ bool self_loops);
using namespace boost::python;
@@ -111,6 +131,9 @@ BOOST_PYTHON_MODULE(libgraph_tool_generation)
def("price", &price);
def("complete", &complete);
def("circular", &circular);
+ def("community_network", &community_network);
+ def("community_network_vavg", &community_network_vavg);
+ def("community_network_eavg", &community_network_eavg);
class_>("Sampler",
init&, const vector&>())
diff --git a/src/graph/generation/sampler.hh b/src/graph/generation/sampler.hh
index b1188a4edfc063ca55ecb041f43b79a5f05f3063..1d1e26b0414c50f59d9d5b1a19cb5eb44d474ebd 100644
--- a/src/graph/generation/sampler.hh
+++ b/src/graph/generation/sampler.hh
@@ -111,7 +111,7 @@ private:
// uniform sampling from containers
template
-const typename Container::value_type& uniform_sample(const Container& v, RNG& rng)
+auto& uniform_sample(Container& v, RNG& rng)
{
std::uniform_int_distribution i_rand(0, v.size() - 1);
return v[i_rand(rng)];
diff --git a/src/graph/graph_bind.cc b/src/graph/graph_bind.cc
index 89cb6315c5d01709d25e0b4dec1add9df1f58fad..21e713b572e13242ea4eb994de94c2fbdd1f1100 100644
--- a/src/graph/graph_bind.cc
+++ b/src/graph/graph_bind.cc
@@ -491,7 +491,8 @@ BOOST_PYTHON_MODULE(libgraph_tool_core)
.def("get_graph_index", &GraphInterface::get_graph_index)
.def("copy_vertex_property", &GraphInterface::copy_vertex_property)
.def("copy_edge_property", &GraphInterface::copy_edge_property)
- .def("get_graph_ptr", &GraphInterface::get_graph_ptr);
+ .def("get_graph_ptr", &GraphInterface::get_graph_ptr)
+ .def("get_graph_view", &GraphInterface::get_graph_view);
class_("vertex_index_map", no_init);
class_("edge_index_map", no_init);
diff --git a/src/graph/graph_filtering.cc b/src/graph/graph_filtering.cc
index 9f3b6448365919cb14679249f980b8f3ea11cc6f..4a98c847ef405ed2cebf0fc0b29d142e9d97da11 100644
--- a/src/graph/graph_filtering.cc
+++ b/src/graph/graph_filtering.cc
@@ -31,6 +31,8 @@ bool graph_tool::graph_filtering_enabled()
#endif
}
+namespace graph_tool
+{
string name_demangle(string name)
{
int status = 0;
@@ -41,6 +43,7 @@ string name_demangle(string name)
free(realname);
return ret;
}
+}
// Whenever no implementation is called, the following exception is thrown
graph_tool::ActionNotFound::ActionNotFound(const type_info& action,
diff --git a/src/graph/graph_filtering.hh b/src/graph/graph_filtering.hh
index 1cbc4c46ee01c18ce189a32fa039479e166ccdc4..dbb83ea6d4acbd0154a3846543ab56ff894079bc 100644
--- a/src/graph/graph_filtering.hh
+++ b/src/graph/graph_filtering.hh
@@ -536,6 +536,8 @@ retrieve_graph_view(GraphInterface& gi, Graph& init)
return *gptr;
}
+// symbol demangling
+string name_demangle(string name);
} //graph_tool namespace
diff --git a/src/graph/graph_properties.hh b/src/graph/graph_properties.hh
index b9350f21ea48d57a487419a91c0592c6d13a0c6a..51cb5b174a16b7b7707d1f856b3b76867f1913f6 100644
--- a/src/graph/graph_properties.hh
+++ b/src/graph/graph_properties.hh
@@ -616,6 +616,9 @@ public:
const value_type c;
};
+template
+void put(const ConstantPropertyMap&, const Key&, const Value&) {}
+
// the following is a property map which always returns one
template
class UnityPropertyMap
@@ -632,6 +635,9 @@ public:
};
+template
+void put(const UnityPropertyMap&, const Key&, const Value&) {}
+
template
struct is_constant_property
{
@@ -642,7 +648,6 @@ struct is_constant_property
typename std::is_same>::type>::type type;
};
-
// this wraps an existing property map, but always converts its values to a
// given type
template
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// as published by the Free Software Foundation; either version 3
+// of the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program. If not, see .
+
+#ifndef SPLIT_MERGE_LOOP_HH
+#define SPLIT_MERGE_LOOP_HH
+
+#include "config.h"
+
+#include
+#include
+
+#include
+
+#include "hash_map_wrap.hh"
+
+#ifdef USING_OPENMP
+#include
+#endif
+namespace graph_tool
+{
+
+template
+auto bundled_vacate_sweep(MergeState& state, RNG& rng)
+{
+ // individual bundles can move in different directions
+ auto get_best_move = [&] (auto& bundle, auto& past_moves)
+ {
+ std::tuple best_move(state._null_move,
+ numeric_limits::max());
+
+ auto r = state.bundle_state(bundle);
+
+ auto find_candidates = [&](bool random)
+ {
+ for (size_t iter = 0; iter < state._niter; ++iter)
+ {
+ auto s = state.move_proposal(bundle, random, rng);
+ if (s == state._null_move)
+ continue;
+ if (past_moves.find(s) != past_moves.end())
+ continue;
+ past_moves.insert(s);
+
+ double dS = state.virtual_move_dS(bundle, s);
+
+ if (dS < get<1>(best_move))
+ {
+ get<0>(best_move) = s;
+ get<1>(best_move) = dS;
+ }
+ }
+ };
+
+ find_candidates(false);
+
+ // if no candidates were found, the group is likely to be "stuck"
+ // (i.e. isolated or constrained by clabel); attempt random
+ // movements instead
+
+ if (get<0>(best_move) == state._null_move)
+ find_candidates(true);
+
+ return best_move;
+ };
+
+ // all bundles move together
+ auto get_best_move_coherent = [&] (auto& bundles)
+ {
+ auto r = state.bundle_state(bundles[0]);
+
+ gt_hash_set past_moves;
+ std::tuple best_move(state._null_move,
+ numeric_limits::max());
+
+ auto find_candidates = [&](bool random)
+ {
+ for (size_t iter = 0; iter < state._niter; ++iter)
+ {
+ auto s = state.move_proposal(uniform_sample(bundles, rng),
+ random, rng);
+ if ( s == state._null_move)
+ continue;
+ if (past_moves.find(s) != past_moves.end())
+ continue;
+ past_moves.insert(s);
+
+ double dS = 0;
+ for (auto& bundle : bundles)
+ {
+ dS += state.virtual_move_dS(bundle, s);
+ state.perform_move(bundle, s);
+ }
+
+ for (auto& bundle : bundles)
+ state.perform_move(bundle, r);
+
+ if (dS < get<1>(best_move))
+ {
+ get<0>(best_move) = s;
+ get<1>(best_move) = dS;
+ }
+ }
+ };
+
+ find_candidates(false);
+
+ // if no candidates were found, the group is likely to be "stuck"
+ // (i.e. isolated or constrained by clabel); attempt random
+ // movements instead
+
+ if (get<0>(best_move) == state._null_move)
+ find_candidates(true);
+
+ return best_move;
+ };
+
+ auto get_best_move_bundles = [&](auto& bundles, auto& forbidden_moves,
+ auto& bmoves)
+ {
+ auto r = state.bundle_state(bundles[0]);
+
+ double dS = 0;
+ for (auto& bundle : bundles)
+ {
+
+ gt_hash_set past_moves(forbidden_moves);
+ auto best_move = get_best_move(bundle, past_moves);
+ if (get<0>(best_move) == state._null_move)
+ {
+ bmoves.clear();
+ break;
+ }
+ bmoves.push_back(get<0>(best_move));
+
+ dS += state.virtual_move_dS(bundle, bmoves.back());
+ state.perform_move(bundle, bmoves.back());
+ }
+
+ for (auto& bundle : bundles)
+ state.perform_move(bundle, r);
+
+ auto best_coherent = get_best_move_coherent(bundles);
+
+ if (get<1>(best_coherent) < dS)
+ {
+ dS = get<1>(best_coherent);
+ for (auto& r : bmoves)
+ r = get<0>(best_coherent);
+ }
+
+ return dS;
+ };
+
+
+ std::vector>>,
+ std::vector>> best_moves;
+ std::vector best_moves_dS;
+ std::vector idx;
+
+ for (auto& bundles : state._block_bundles)
+ {
+ std::vector bmoves;
+ gt_hash_set past_moves;
+ double dS = get_best_move_bundles(bundles, past_moves, bmoves);
+ if (!bmoves.empty())
+ {
+ best_moves.emplace_back(std::ref(bundles),
+ std::move(bmoves));
+ best_moves_dS.push_back(dS);
+ idx.push_back(idx.size());
+ }
+ }
+
+ std::shuffle(idx.begin(), idx.end(), rng);
+
+ auto cmp = [&](auto& i, auto& j)
+ { return best_moves_dS[i] > best_moves_dS[j]; };
+
+ std::priority_queue, decltype(cmp)> queue(cmp);
+
+ for (auto i : idx)
+ queue.push(i);
+
+ double S = 0;
+ size_t nmerges = 0;
+ gt_hash_set vacated;
+ while (nmerges != state._nmerges && !queue.empty())
+ {
+ auto pos = queue.top();
+ queue.pop();
+
+ auto& bundles = get<0>(best_moves[pos]).get();
+ auto& bmoves = get<1>(best_moves[pos]);
+
+ bool redo = false;
+ for (auto s : bmoves)
+ {
+ if (vacated.find(s) != vacated.end())
+ {
+ redo = true;
+ break;
+ }
+ }
+
+ if (redo)
+ {
+ bmoves.clear();
+ double dS = get_best_move_bundles(bundles, vacated, bmoves);
+ if (bmoves.empty())
+ continue;
+ if (!queue.empty() && best_moves_dS[queue.top()] < dS)
+ {
+ best_moves_dS[pos] = dS;
+ queue.push(pos);
+ continue;
+ }
+ }
+
+ auto r = state.bundle_state(bundles[0]);
+ vacated.insert(r);
+
+ for (size_t i = 0; i < bundles.size(); ++i)
+ {
+ auto& bundle = bundles[i];
+ auto s = bmoves[i];
+ S += state.virtual_move_dS(bundle, s);
+ state.perform_move(bundle, s);
+ }
+
+ nmerges++;
+ }
+
+ return make_pair(S, nmerges);
+}
+
+} // graph_tool namespace
+
+#endif //SPLIT_MERGE_LOOP_HH
diff --git a/src/graph/inference/cache.cc b/src/graph/inference/cache.cc
new file mode 100644
index 0000000000000000000000000000000000000000..4fad8fdf5a2b823a7c280b00487ce01c577deef3
--- /dev/null
+++ b/src/graph/inference/cache.cc
@@ -0,0 +1,86 @@
+// graph-tool -- a general graph modification and manipulation thingy
+//
+// Copyright (C) 2006-2016 Tiago de Paula Peixoto
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// as published by the Free Software Foundation; either version 3
+// of the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program. If not, see .
+
+#include "cache.hh"
+
+namespace graph_tool
+{
+
+using namespace std;
+
+vector __safelog_cache;
+vector __xlogx_cache;
+vector __lgamma_cache;
+
+void init_safelog(size_t x)
+{
+ size_t old_size = __safelog_cache.size();
+ if (x >= old_size)
+ {
+ __safelog_cache.resize(x + 1);
+ for (size_t i = old_size; i < __safelog_cache.size(); ++i)
+ __safelog_cache[i] = safelog(double(i));
+ }
+}
+
+void clear_safelog()
+{
+ vector().swap(__safelog_cache);
+}
+
+
+void init_xlogx(size_t x)
+{
+ size_t old_size = __xlogx_cache.size();
+ if (x >= old_size)
+ {
+ __xlogx_cache.resize(x + 1);
+ for (size_t i = old_size; i < __xlogx_cache.size(); ++i)
+ __xlogx_cache[i] = i * safelog(i);
+ }
+}
+
+void clear_xlogx()
+{
+ vector().swap(__xlogx_cache);
+}
+
+void init_lgamma(size_t x)
+{
+ size_t old_size = __lgamma_cache.size();
+ if (x >= old_size)
+ {
+ __lgamma_cache.resize(x + 1);
+ for (size_t i = old_size; i < __lgamma_cache.size(); ++i)
+ __lgamma_cache[i] = lgamma(i);
+ }
+}
+
+void clear_lgamma()
+{
+ vector().swap(__lgamma_cache);
+}
+
+void init_cache(size_t E)
+{
+ init_lgamma(2 * E);
+ init_xlogx(2 * E);
+ init_safelog(2 * E);
+}
+
+
+} // namespace graph_tool
diff --git a/src/graph/inference/cache.hh b/src/graph/inference/cache.hh
new file mode 100644
index 0000000000000000000000000000000000000000..66daa0f0da448046c8be0d735695b44f862888ac
--- /dev/null
+++ b/src/graph/inference/cache.hh
@@ -0,0 +1,78 @@
+// graph-tool -- a general graph modification and manipulation thingy
+//
+// Copyright (C) 2006-2016 Tiago de Paula Peixoto
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// as published by the Free Software Foundation; either version 3
+// of the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program. If not, see .
+
+#ifndef CACHE_HH
+#define CACHE_HH
+
+#include "config.h"
+
+#include
+#include
+
+namespace graph_tool
+{
+using namespace std;
+
+// Repeated computation of x*log(x) and log(x) actually adds up to a lot of
+// time. A significant speedup can be made by caching pre-computed values.
+
+extern vector __safelog_cache;
+extern vector __xlogx_cache;
+extern vector __lgamma_cache;
+
+void init_safelog(size_t x);
+
+template
+inline double safelog(Type x)
+{
+ if (x == 0)
+ return 0;
+ return log(x);
+}
+
+inline double safelog(size_t x)
+{
+ if (x >= __safelog_cache.size())
+ init_safelog(x);
+ return __safelog_cache[x];
+}
+
+void init_xlogx(size_t x);
+
+inline double xlogx(size_t x)
+{
+ //return x * safelog(x);
+ if (x >= __xlogx_cache.size())
+ init_xlogx(x);
+ return __xlogx_cache[x];
+}
+
+void init_lgamma(size_t x);
+
+inline double lgamma_fast(size_t x)
+{
+ //return lgamma(x);
+ if (x >= __lgamma_cache.size())
+ init_lgamma(x);
+ return __lgamma_cache[x];
+}
+
+void init_cache(size_t E);
+
+} // graph_tool namespace
+
+#endif //CACHE_HH
diff --git a/src/graph/inference/gibbs_loop.hh b/src/graph/inference/gibbs_loop.hh
new file mode 100644
index 0000000000000000000000000000000000000000..f8a89ef7b0c26c69a3697f37edeb13149fc805d6
--- /dev/null
+++ b/src/graph/inference/gibbs_loop.hh
@@ -0,0 +1,181 @@
+// graph-tool -- a general graph modification and manipulation thingy
+//
+// Copyright (C) 2006-2016 Tiago de Paula Peixoto
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// as published by the Free Software Foundation; either version 3
+// of the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program. If not, see .
+
+#ifndef GIBBS_LOOP_HH
+#define GIBBS_LOOP_HH
+
+#include "config.h"
+
+#include
+#include
+
+#include
+
+#include "hash_map_wrap.hh"
+#include "parallel_rng.hh"
+
+#ifdef USING_OPENMP
+#include
+#endif
+namespace graph_tool
+{
+
+template
+auto gibbs_sweep(GibbsState state, RNG& rng_)
+{
+ auto& g = state._g;
+
+ vector> rngs;
+ std::vector> best_move;
+
+ if (state._parallel)
+ {
+ init_rngs(rngs, rng_);
+ init_cache(state._E);
+ best_move.resize(num_vertices(g));
+ }
+
+ auto& vlist = state._vlist;
+ auto beta = state._beta;
+
+ vector probs;
+ vector deltas;
+ vector idx;
+
+ double S = 0;
+ size_t nmoves = 0;
+
+ for (size_t iter = 0; iter < state._niter; ++iter)
+ {
+ if (!state._parallel)
+ {
+ std::shuffle(vlist.begin(), vlist.end(), rng_);
+ }
+ else
+ {
+ parallel_loop(vlist,
+ [&](auto v)
+ {
+ best_move[v] =
+ std::make_pair(state.node_state(v),
+ numeric_limits::max());
+ });
+ }
+
+ size_t i = 0, N = vlist.size();
+ #pragma omp parallel for default(shared) private(i) \
+ firstprivate(state, probs, deltas, idx) \
+ schedule(runtime) if (state._parallel)
+ for (i = 0; i < N; ++i)
+ {
+ auto& rng = get_rng(rngs, rng_);
+
+ size_t v;
+ if (state._sequential)
+ {
+ v = vertex(vlist[i], g);
+ }
+ else
+ {
+ std::uniform_int_distribution v_rand(0, N - 1);
+ v = vertex(vlist[v_rand(rng)], g);
+ }
+
+ vector& moves = state.get_moves(v);
+ auto& weights = state.get_weights(v);
+
+ probs.resize(moves.size());
+ deltas.resize(moves.size());
+ idx.resize(moves.size());
+
+ double dS_min = numeric_limits::max();
+ for (size_t j = 0; j < moves.size(); ++j)
+ {
+ size_t s = moves[j];
+ double dS = state.virtual_move_dS(v, s);
+ dS_min = std::min(dS, dS_min);
+ deltas[j] = dS;
+ idx[j] = j;
+ }
+
+ if (!isinf(beta))
+ {
+ for (size_t j = 0; j < moves.size(); ++j)
+ {
+ if (std::isinf(deltas[j]))
+ probs[j] = 0;
+ else
+ probs[j] = exp((-deltas[j] + dS_min) * beta) * weights[j];
+ }
+ }
+ else
+ {
+ for (size_t j = 0; j < moves.size(); ++j)
+ probs[j] = (deltas[j] == dS_min) ? weights[j] : 0;
+ }
+
+ Sampler sampler(idx, probs);
+
+ size_t j = sampler.sample(rng);
+
+ assert(probs[j] > 0);
+
+ size_t s = moves[j];
+ size_t r = state.node_state(v);
+
+ if (s == r)
+ continue;
+
+ if (!state._parallel)
+ {
+ state.perform_move(v, s);
+ nmoves++;
+ S += deltas[j];
+ }
+ else
+ {
+ best_move[v].first = s;
+ best_move[v].second = deltas[j];
+ }
+ }
+
+ if (state._parallel)
+ {
+ for (auto v : vlist)
+ {
+ auto s = best_move[v].first;
+ double dS = best_move[v].second;
+ if (dS != numeric_limits::max())
+ {
+ dS = state.virtual_move_dS(v, s);
+
+ if (dS > 0 && std::isinf(beta))
+ continue;
+
+ state.perform_move(v, s);
+ nmoves++;
+ S += dS;
+ }
+ }
+ }
+ }
+ return make_pair(S, nmoves);
+}
+
+} // graph_tool namespace
+
+#endif //GIBBS_LOOP_HH
diff --git a/src/graph/inference/graph_blockmodel.cc b/src/graph/inference/graph_blockmodel.cc
new file mode 100644
index 0000000000000000000000000000000000000000..6a0fd977e7c20191a02614c4d3be03cf620022ed
--- /dev/null
+++ b/src/graph/inference/graph_blockmodel.cc
@@ -0,0 +1,271 @@
+// graph-tool -- a general graph modification and manipulation thingy
+//
+// Copyright (C) 2006-2016 Tiago de Paula Peixoto
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// as published by the Free Software Foundation; either version 3
+// of the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program. If not, see .
+
+#include "graph_tool.hh"
+#include "random.hh"
+
+#include
+
+#include "graph_blockmodel_util.hh"
+#include "graph_blockmodel.hh"
+#include "graph_state.hh"
+
+using namespace boost;
+using namespace graph_tool;
+
+GEN_DISPATCH(block_state, BlockState, BLOCK_STATE_params)
+
+python::object make_block_state(boost::python::object ostate,
+ rng_t& rng)
+{
+ python::object state;
+ block_state::make_dispatch(ostate,
+ [&](auto& s){state = python::object(s);},
+ rng);
+ return state;
+}
+
+degs_map_t get_block_degs(GraphInterface& gi, boost::any ab)
+{
+ degs_map_t degs;
+ vmap_t b = boost::any_cast(ab);
+ run_action<>()(gi,
+ [&](auto& g)
+ {
+ std::vector,
+ size_t>> hist;
+ for (auto v : vertices_range(g))
+ {
+ size_t r = b[v];
+ if (r >= hist.size())
+ hist.resize(r + 1);
+ size_t kin = in_degreeS()(v, g);
+ size_t kout = out_degreeS()(v, g);
+ hist[r][std::make_tuple(kin, kout)]++;
+ }
+
+ for (size_t r = 0; r < hist.size(); ++r)
+ {
+ auto& deg = degs[r];
+ for (auto& kn : hist[r])
+ deg.emplace_back(get<0>(kn.first),
+ get<1>(kn.first),
+ kn.second);
+ }
+ })();
+ return degs;
+}
+
+degs_map_t get_weighted_block_degs(GraphInterface& gi, degs_map_t& degs,
+ boost::any ab)
+{
+ degs_map_t ndegs;
+ vmap_t b = boost::any_cast(ab);
+ run_action<>()(gi,
+ [&](auto& g)
+ {
+ std::vector,
+ size_t>> hist;
+ for (auto v : vertices_range(g))
+ {
+ size_t r = b[v];
+ if (r >= hist.size())
+ hist.resize(r + 1);
+ auto& h = hist[r];
+ auto& ks = degs[v];
+ for (auto& k : ks)
+ h[std::make_tuple(get<0>(k), get<1>(k))] += get<2>(k);
+ }
+
+ for (size_t r = 0; r < hist.size(); ++r)
+ {
+ auto& deg = ndegs[r];
+ for (auto& kn : hist[r])
+ deg.emplace_back(get<0>(kn.first),
+ get<1>(kn.first),
+ kn.second);
+ }
+ })();
+ return ndegs;
+}
+
+
+template
+boost::any get_any(Prop& p)
+{
+ return any(p);
+}
+
+void print_degs(degs_map_t& degs, size_t B)
+{
+ for (size_t r = 0; r < B; ++r)
+ {
+ cout << r << ":: ";
+ auto& ks = degs[r];
+ for (auto& k : ks)
+ {
+ cout << "(" << get<0>(k) << ", " << get<1>(k) << "): "
+ << get<2>(k) << " ";
+ }
+ cout << endl;
+ }
+}
+
+degs_map_t copy_degs(degs_map_t& degs)
+{
+ return degs.copy();
+}
+
+simple_degs_t copy_simple_degs(simple_degs_t& degs)
+{
+ return degs;
+}
+
+boost::python::tuple bethe_entropy(GraphInterface& gi, size_t B, boost::any op,
+ boost::any opv)
+{
+ typedef vprop_map_t>::type vmap_t;
+ typedef eprop_map_t>::type emap_t;
+ emap_t p = any_cast(op);
+ vmap_t pv = any_cast(opv);
+
+ double H=0, sH=0, Hmf=0, sHmf=0;
+ run_action()
+ (gi,
+ [&](auto& g)
+ {
+ for (auto v : vertices_range(g))
+ {
+ pv[v].resize(B);
+ for (size_t i = 0; i < B; ++i)
+ pv[v][i] = 0;
+ }
+
+ H = Hmf = sH = sHmf = 0;
+
+ for (auto e : edges_range(g))
+ {
+ auto u = min(source(e, g), target(e, g));
+ auto v = max(source(e, g), target(e, g));
+
+ double sum = 0;
+ for (size_t r = 0; r < B; ++r)
+ for (size_t s = 0; s < B; ++s)
+ {
+ size_t i = r + B * s;
+ pv[u][r] += p[e][i];
+ pv[v][s] += p[e][i];
+ sum += p[e][i];
+ }
+
+ for (size_t i = 0; i < B * B; ++i)
+ {
+ if (p[e][i] == 0)
+ continue;
+ double pi = double(p[e][i]) / sum;
+ H -= pi * log(pi);
+ sH += pow((log(pi) + 1) * sqrt(pi / sum), 2);
+ }
+ }
+
+ for (auto v : vertices_range(g))
+ {
+ double sum = 0;
+ for (size_t i = 0; i < B; ++i)
+ sum += pv[v][i];
+ for (size_t i = 0; i < B; ++i)
+ {
+ if (pv[v][i] == 0)
+ continue;
+ pv[v][i] /= sum;
+ double pi = pv[v][i];
+ double kt = (1 - double(in_degreeS()(v, g)) - double(out_degree(v, g)));
+ if (kt != 0)
+ {
+ H -= kt * (pi * log(pi));
+ sH += pow(kt * (log(pi) + 1) * sqrt(pi / sum), 2);
+ }
+
+ Hmf -= pi * log(pi);
+ sHmf += pow((log(pi) + 1) * sqrt(pi / sum), 2);
+ }
+ }
+ })();
+
+ return boost::python::make_tuple(H, sH, Hmf, sHmf);
+}
+
+
+void export_blockmodel_state()
+{
+ using namespace boost::python;
+
+ block_state::dispatch
+ ([&](auto* s)
+ {
+ typedef typename std::remove_reference::type state_t;
+
+ double (state_t::*virtual_move)(size_t, size_t, bool, bool, bool,
+ bool, bool) =
+ &state_t::virtual_move;
+ size_t (state_t::*sample_block)(size_t, double, vector&,
+ rng_t&)
+ = &state_t::sample_block;
+ double (state_t::*get_move_prob)(size_t, size_t, size_t, double,
+ bool)
+ = &state_t::get_move_prob;
+ void (state_t::*merge_vertices)(size_t, size_t)
+ = &state_t::merge_vertices;
+
+ class_ c(name_demangle(typeid(state_t).name()).c_str(),
+ no_init);
+ c.def("remove_vertex", &state_t::remove_vertex)
+ .def("add_vertex", &state_t::add_vertex)
+ .def("move_vertex", &state_t::move_vertex)
+ .def("virtual_move", virtual_move)
+ .def("merge_vertices", merge_vertices)
+ .def("sample_block", sample_block)
+ .def("entropy", &state_t::entropy)
+ .def("get_partition_dl", &state_t::get_partition_dl)
+ .def("get_deg_dl", &state_t::get_deg_dl)
+ .def("get_move_prob", get_move_prob)
+ .def("enable_partition_stats",
+ &state_t::enable_partition_stats)
+ .def("disable_partition_stats",
+ &state_t::disable_partition_stats)
+ .def("is_partition_stats_enabled",
+ &state_t::is_partition_stats_enabled);
+ });
+
+ class_("unity_vprop_t").def("_get_any", &get_any);
+ class_("unity_eprop_t").def("_get_any", &get_any);
+
+ def("make_block_state", &make_block_state);
+
+ class_("true_type");
+ class_("false_type");
+
+ def("get_block_degs", &get_block_degs);
+ def("get_weighted_block_degs", &get_weighted_block_degs);
+ class_("degs_map_t")
+ .def("print", &print_degs)
+ .def("copy", ©_degs);
+ class_("simple_degs_t")
+ .def("copy", ©_simple_degs);
+
+ def("bethe_entropy", &bethe_entropy);
+}
diff --git a/src/graph/inference/graph_blockmodel.hh b/src/graph/inference/graph_blockmodel.hh
new file mode 100644
index 0000000000000000000000000000000000000000..da694332a10177978ac02f16ccd44d95a5bc6be6
--- /dev/null
+++ b/src/graph/inference/graph_blockmodel.hh
@@ -0,0 +1,1052 @@
+// graph-tool -- a general graph modification and manipulation thingy
+//
+// Copyright (C) 2006-2016 Tiago de Paula Peixoto
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// as published by the Free Software Foundation; either version 3
+// of the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program. If not, see .
+
+#ifndef GRAPH_BLOCKMODEL_HH
+#define GRAPH_BLOCKMODEL_HH
+
+#include "config.h"
+
+#include
+
+#include "graph_state.hh"
+#include "graph_blockmodel_util.hh"
+
+namespace graph_tool
+{
+using namespace boost;
+using namespace std;
+
+typedef vprop_map_t::type vmap_t;
+typedef eprop_map_t::type emap_t;
+typedef UnityPropertyMap vcmap_t;
+typedef UnityPropertyMap ecmap_t;
+
+typedef mpl::vector2 eweight_tr;
+typedef mpl::vector2 vweight_tr;
+typedef mpl::vector2 use_hash_tr;
+typedef mpl::vector2 degs_tr;
+
+#define BLOCK_STATE_params \
+ ((g, &, all_graph_views, 1)) \
+ ((degs,, degs_tr, 1)) \
+ ((eweight,, eweight_tr, 1)) \
+ ((vweight,, vweight_tr, 1)) \
+ ((use_hash,, use_hash_tr, 1)) \
+ ((_abg, &, boost::any&, 0)) \
+ ((mrs,, emap_t, 0)) \
+ ((mrp,, vmap_t, 0)) \
+ ((mrm,, vmap_t, 0)) \
+ ((wr,, vmap_t, 0)) \
+ ((b,, vmap_t, 0)) \
+ ((bclabel,, vmap_t, 0)) \
+ ((pclabel,, vmap_t, 0)) \
+ ((merge_map,, vmap_t, 0)) \
+ ((deg_corr,, bool, 0)) \
+ ((ignore_degree,, typename vprop_map_t::type, 0))
+
+GEN_STATE_BASE(BlockStateBase, BLOCK_STATE_params)
+
+template
+class BlockState
+ : public BlockStateBase
+{
+public:
+ GET_PARAMS_USING(BlockStateBase, BLOCK_STATE_params)
+ GET_PARAMS_TYPEDEF(Ts, BLOCK_STATE_params)
+
+ template * = nullptr>
+ BlockState(RNG& rng, ATs&&... args)
+ : BlockStateBase(std::forward(args)...),
+ _bg(boost::any_cast>(__abg)),
+ _c_mrs(_mrs.get_checked()),
+ _emat(_g, _b, _bg, rng),
+ _neighbour_sampler(get(vertex_index_t(), _g), num_vertices(_g)),
+ _m_entries(num_vertices(_bg))
+ {
+ init_neighbour_sampler(_g, _eweight, _neighbour_sampler);
+ }
+
+ BlockState(const BlockState& other)
+ : BlockStateBase(static_cast&>(other)),
+ _bg(boost::any_cast>(__abg)),
+ _c_mrs(_mrs.get_checked()),
+ _emat(other._emat),
+ _neighbour_sampler(other._neighbour_sampler),
+ _m_entries(num_vertices(_bg))
+ {
+ if (other.is_partition_stats_enabled())
+ enable_partition_stats();
+ }
+
+ // remove a vertex from its current block
+ void remove_vertex(size_t v)
+ {
+ typedef typename graph_traits::vertex_descriptor vertex_t;
+
+ vertex_t r = _b[v];
+
+ int self_weight = 0;
+ for (auto e : out_edges_range(v, _g))
+ {
+ vertex_t u = target(e, _g);
+ vertex_t s = _b[u];
+
+ auto& me = _emat.get_bedge(e);
+
+ size_t ew = _eweight[e];
+ if (u == v && !is_directed::apply::type::value)
+ {
+ self_weight += ew;
+ }
+ else
+ {
+ _mrs[me] -= ew;
+
+ assert(_mrs[me] >= 0);
+
+ _mrp[r] -= ew;
+ _mrm[s] -= ew;
+
+ if (_mrs[me] == 0)
+ _emat.remove_me(r, s, me, _bg);
+ }
+ }
+
+ if (self_weight > 0)
+ {
+ assert(self_weight % 2 == 0);
+ const auto& me = _emat.get_me(r, r);
+ _mrs[me] -= self_weight / 2;
+ _mrp[r] -= self_weight / 2;
+ _mrm[r] -= self_weight / 2;
+ assert(_mrs[me] >= 0);
+ if (_mrs[me] == 0)
+ _emat.remove_me(r, r, me, _bg);
+ }
+
+ for (auto e : in_edges_range(v, _g))
+ {
+ vertex_t u = source(e, _g);
+ if (u == v)
+ continue;
+ vertex_t s = _b[u];
+
+ auto& me = _emat.get_bedge(e);
+
+ size_t ew = _eweight[e];
+ _mrs[me] -= ew;
+
+ _mrp[s] -= ew;
+ _mrm[r] -= ew;
+
+ if (_mrs[me] == 0)
+ _emat.remove_me(s, r, me, _bg);
+ }
+
+ _wr[r] -= _vweight[v];
+
+ if (!_egroups.empty())
+ _egroups.remove_vertex(v, r, _g);
+
+ if (is_partition_stats_enabled())
+ get_partition_stats(v).remove_vertex(v, r, _deg_corr, _g, _vweight,
+ _eweight, _degs);
+ }
+
+ // add a vertex to block r
+ void add_vertex(size_t v, size_t r)
+ {
+ typedef typename graph_traits::vertex_descriptor vertex_t;
+ typedef typename graph_traits::edge_descriptor bedge_t;
+
+ int self_weight = 0;
+ for (auto e : out_edges_range(v, _g))
+ {
+ vertex_t u = target(e, _g);
+ vertex_t s;
+
+ if (u != v)
+ s = _b[u];
+ else
+ s = r;
+
+ auto me = _emat.get_me(r, s);
+
+ if (me == bedge_t())
+ {
+ me = add_edge(r, s, _bg).first;
+ _emat.put_me(r, s, me);
+ _c_mrs[me] = 0;
+ }
+
+ _emat.get_bedge(e) = me;
+
+ assert(_emat.get_bedge(e) != bedge_t());
+ assert(me == _emat.get_me(r, s));
+
+ size_t ew = _eweight[e];
+
+ if (u == v && !is_directed::apply::type::value)
+ {
+ self_weight += ew;
+ }
+ else
+ {
+ _mrs[me] += ew;
+ _mrp[r] += ew;
+ _mrm[s] += ew;
+ }
+ }
+
+ if (self_weight > 0)
+ {
+ assert(self_weight % 2 == 0);
+ const auto& me = _emat.get_me(r, r);
+ _mrs[me] += self_weight / 2;
+ _mrp[r] += self_weight / 2;
+ _mrm[r] += self_weight / 2;
+ assert(_mrs[me] >= 0);
+ }
+
+ for (auto e : in_edges_range(v, _g))
+ {
+ vertex_t u = source(e, _g);
+ if (u == v)
+ continue;
+
+ vertex_t s = _b[u];
+
+ auto me = _emat.get_me(s, r);
+
+ if (me == bedge_t())
+ {
+ me = add_edge(s, r, _bg).first;
+ _emat.put_me(s, r, me);
+ _c_mrs[me] = 0;
+ }
+ _emat.get_bedge(e) = me;
+
+ assert(_emat.get_bedge(e) != bedge_t());
+ assert(me == _emat.get_me(s, r));
+
+ size_t ew = _eweight[e];
+
+ _mrs[me] += ew;
+
+ _mrp[s] += ew;
+ _mrm[r] += ew;
+ }
+
+ _wr[r] += _vweight[v];
+ _b[v] = r;
+
+ if (!_egroups.empty())
+ _egroups.add_vertex(v, r, _eweight, _g);
+
+ if (is_partition_stats_enabled())
+ get_partition_stats(v).add_vertex(v, r, _deg_corr, _g, _vweight,
+ _eweight, _degs);
+ }
+
+ // move a vertex from its current block to block nr
+ void move_vertex(size_t v, size_t nr)
+ {
+ size_t r = _b[v];
+ if (r == nr)
+ return;
+ if (_bclabel[r] != _bclabel[nr])
+ throw ValueException("cannot move vertex across clabel barriers");
+ remove_vertex(v);
+ add_vertex(v, nr);
+ }
+
+ size_t virtual_remove_size(size_t v)
+ {
+ return _wr[_b[v]] - _vweight[v];
+ }
+
+ // merge vertex u into v
+ void merge_vertices(size_t u, size_t v)
+ {
+ typedef typename graph_traits::edge_descriptor edge_t;
+ UnityPropertyMap dummy;
+ merge_vertices(u, v, dummy);
+ }
+
+ template
+ void merge_vertices(size_t u, size_t v, Emap& ec)
+ {
+ if (u == v)
+ return;
+ merge_vertices(u, v, ec,
+ typename is_constant_property::type(),
+ typename is_constant_property::type());
+ }
+
+ template
+ void merge_vertices(size_t, size_t, Emap&, T1, T2)
+ {
+ throw ValueException("cannot merge vertices of unweighted graph");
+ }
+
+ template
+ void merge_vertices(size_t u, size_t v, Emap& ec, std::false_type,
+ std::false_type)
+ {
+ auto eweight_c = _eweight.get_checked();
+ auto bedge_c = _emat.get_bedge_map().get_checked();
+
+ typedef typename graph_traits::vertex_descriptor vertex_t;
+ typedef typename graph_traits::edge_descriptor edge_t;
+
+ gt_hash_map, vector> ns_u, ns_v;
+ for(auto e : out_edges_range(u, _g))
+ ns_u[std::make_tuple(target(e, _g), ec[e])].push_back(e);
+ for(auto e : out_edges_range(v, _g))
+ ns_v[std::make_tuple(target(e, _g), ec[e])].push_back(e);
+
+ for(auto& kv : ns_u)
+ {
+ vertex_t t = get<0>(kv.first);
+ int l = get<1>(kv.first);
+ auto& es = kv.second;
+
+ size_t w = 0;
+ for (auto& e : es)
+ w += _eweight[e];
+
+ if (t == u)
+ {
+ t = v;
+ if (!is_directed::apply::type::value)
+ {
+ assert(w % 2 == 0);
+ w /= 2;
+ }
+ }
+
+ auto iter = ns_v.find(std::make_tuple(t, l));
+ if (iter != ns_v.end())
+ {
+ auto& e = iter->second.front();
+ _eweight[e] += w;
+ }
+ else
+ {
+ auto e = add_edge(v, t, _g).first;
+ ns_v[std::make_tuple(t, l)].push_back(e);
+ eweight_c[e] = w;
+ bedge_c[e] = bedge_c[es.front()];
+ set_prop(ec, e, l);
+ }
+ }
+
+ if (is_directed::apply::type::value)
+ {
+ ns_u.clear();
+ ns_v.clear();
+
+ for(auto e : in_edges_range(v, _g))
+ ns_v[std::make_tuple(source(e, _g), ec[e])].push_back(e);
+ for(auto e : in_edges_range(u, _g))
+ ns_u[std::make_tuple(source(e, _g), ec[e])].push_back(e);
+
+ for(auto& kv : ns_u)
+ {
+ vertex_t s = get<0>(kv.first);
+ int l = get<1>(kv.first);
+ auto& es = kv.second;
+
+ if (s == u)
+ continue;
+
+ size_t w = 0;
+ for (auto& e : es)
+ w += _eweight[e];
+
+ auto iter = ns_v.find(std::make_tuple(s, l));
+ if (iter != ns_v.end())
+ {
+ auto& e = iter->second.front();
+ _eweight[e] += w;
+ }
+ else
+ {
+ auto e = add_edge(s, v, _g).first;
+ ns_v[std::make_tuple(s, l)].push_back(e);
+ eweight_c[e] = w;
+ bedge_c[e] = bedge_c[es.front()];
+ set_prop(ec, e, l);
+ }
+ }
+ }
+
+ _vweight[v] +=_vweight[u];
+ _vweight[u] = 0;
+ for (auto e : all_edges_range(u, _g))
+ _eweight[e] = 0;
+ clear_vertex(u, _g);
+ _merge_map[u] = v;
+ merge_degs(u, v, _degs);
+ }
+
+ template
+ void set_prop(EMap& ec, Edge& e, Val& val)
+ {
+ ec[e] = val;
+ }
+
+ template
+ void set_prop(UnityPropertyMap&, Edge&, Val&)
+ {
+ }
+
+ void merge_degs(size_t, size_t, const simple_degs_t&) {}
+
+ void merge_degs(size_t u, size_t v, typename degs_map_t::unchecked_t& degs)
+ {
+ gt_hash_map, size_t> hist;
+ for (auto& kn : degs[u])
+ hist[make_tuple(get<0>(kn), get<1>(kn))] += get<2>(kn);
+ for (auto& kn : degs[v])
+ hist[make_tuple(get<0>(kn), get<1>(kn))] += get<2>(kn);
+ degs[u].clear();
+ degs[v].clear();
+ auto& d = degs[v];
+ for (auto& kn : hist)
+ d.emplace_back(get<0>(kn.first), get<1>(kn.first), kn.second);
+ }
+
+ // compute the entropy difference of a virtual move of vertex from block r to nr
+ template
+ double virtual_move_sparse(size_t v, size_t nr, MEntries& m_entries)
+ {
+ size_t r = _b[v];
+
+ if (r == nr)
+ return 0.;
+
+ m_entries.clear();
+ move_entries(v, nr, _b, _eweight, _mrs, _emat.get_bedge_map(), _g, _bg,
+ m_entries);
+
+ size_t kout = out_degreeS()(v, _g, _eweight);
+ size_t kin = kout;
+ if (is_directed::apply::type::value)
+ kin = in_degreeS()(v, _g, _eweight);
+
+ double dS = entries_dS(m_entries, _mrs, _emat, _bg);
+
+ int dwr = _vweight[v];
+ int dwnr = dwr;
+
+ dS += vterm(_mrp[r] - kout, _mrm[r] - kin, _wr[r] - dwr , _deg_corr, _bg);
+ dS += vterm(_mrp[nr] + kout, _mrm[nr] + kin, _wr[nr] + dwnr, _deg_corr, _bg);
+ dS -= vterm(_mrp[r] , _mrm[r] , _wr[r] , _deg_corr, _bg);
+ dS -= vterm(_mrp[nr] , _mrm[nr] , _wr[nr] , _deg_corr, _bg);
+
+ return dS;
+ }
+
+ double virtual_move_sparse(size_t v, size_t nr)
+ {
+ return virtual_move_sparse(v, nr, _m_entries);
+ }
+
+ template
+ double virtual_move_dense(size_t v, size_t nr, bool multigraph,
+ MEntries& m_entries)
+ {
+ if (_deg_corr)
+ throw GraphException("Dense entropy for degree corrected model not implemented!");
+
+ typedef typename graph_traits::vertex_descriptor vertex_t;
+ vertex_t r = _b[v];
+
+ if (r == nr)
+ return 0;
+
+ // m_entries is not used in the computation below, but it is expected afterwards
+ m_entries.clear();
+ int kin = 0, kout = 0;
+ move_entries(v, nr, _b, _eweight, _mrs, _emat.get_bedge_map(), _g, _bg,
+ m_entries);
+ kout += out_degreeS()(v, _g, _eweight);
+ if (is_directed::apply::type::value)
+ kin += in_degreeS()(v, _g, _eweight);
+
+ vector deltap(num_vertices(_bg), 0);
+ int deltal = 0;
+ for (auto e : out_edges_range(v, _g))
+ {
+ vertex_t u = target(e, _g);
+ vertex_t s = _b[u];
+ if (u == v)
+ deltal += _eweight[e];
+ else
+ deltap[s] += _eweight[e];
+ }
+ if (!is_directed::apply::type::value)
+ deltal /= 2;
+
+ vector deltam(num_vertices(_bg), 0);
+ for (auto e : in_edges_range(v, _g))
+ {
+ vertex_t u = source(e, _g);
+ if (u == v)
+ continue;
+ vertex_t s = _b[u];
+ deltam[s] += _eweight[e];
+ }
+
+ double dS = 0;
+ int dwr = _vweight[v];
+ int dwnr = dwr;
+
+ double Si = 0, Sf = 0;
+ for (vertex_t s = 0; s < num_vertices(_bg); ++s)
+ {
+ int ers = get_mrs(r, s, _mrs, _emat);
+ int enrs = get_mrs(nr, s, _mrs, _emat);
+
+ if (!is_directed::apply::type::value)
+ {
+ if (s != nr && s != r)
+ {
+ Si += eterm_dense(r, s, ers, _wr[r], _wr[s], multigraph, _bg);
+ Sf += eterm_dense(r, s, ers - deltap[s], _wr[r] - dwr, _wr[s], multigraph, _bg);
+ Si += eterm_dense(nr, s, enrs, _wr[nr], _wr[s], multigraph, _bg);
+ Sf += eterm_dense(nr, s, enrs + deltap[s], _wr[nr] + dwnr, _wr[s], multigraph, _bg);
+ }
+
+ if (s == r)
+ {
+ Si += eterm_dense(r, r, ers, _wr[r], _wr[r], multigraph, _bg);
+ Sf += eterm_dense(r, r, ers - deltap[r] - deltal, _wr[r] - dwr, _wr[r] - dwr, multigraph, _bg);
+ }
+
+ if (s == nr)
+ {
+ Si += eterm_dense(nr, nr, enrs, _wr[nr], _wr[nr], multigraph, _bg);
+ Sf += eterm_dense(nr, nr, enrs + deltap[nr] + deltal, _wr[nr] + dwnr, _wr[nr] + dwnr, multigraph, _bg);
+
+ Si += eterm_dense(r, nr, ers, _wr[r], _wr[nr], multigraph, _bg);
+ Sf += eterm_dense(r, nr, ers - deltap[nr] + deltap[r], _wr[r] - dwr, _wr[nr] + dwnr, multigraph, _bg);
+ }
+ }
+ else
+ {
+ int esr = get_mrs(s, r, _mrs, _emat);
+ int esnr = get_mrs(s, nr, _mrs, _emat);
+
+ if (s != nr && s != r)
+ {
+ Si += eterm_dense(r, s, ers , _wr[r] , _wr[s] , multigraph, _bg);
+ Sf += eterm_dense(r, s, ers - deltap[s], _wr[r] - dwr, _wr[s] , multigraph, _bg);
+ Si += eterm_dense(s, r, esr , _wr[s] , _wr[r] , multigraph, _bg);
+ Sf += eterm_dense(s, r, esr - deltam[s], _wr[s] , _wr[r] - dwr, multigraph, _bg);
+
+ Si += eterm_dense(nr, s, enrs , _wr[nr] , _wr[s] , multigraph, _bg);
+ Sf += eterm_dense(nr, s, enrs + deltap[s], _wr[nr] + dwnr, _wr[s] , multigraph, _bg);
+ Si += eterm_dense(s, nr, esnr , _wr[s] , _wr[nr] , multigraph, _bg);
+ Sf += eterm_dense(s, nr, esnr + deltam[s], _wr[s] , _wr[nr] + dwnr, multigraph, _bg);
+ }
+
+ if(s == r)
+ {
+ Si += eterm_dense(r, r, ers , _wr[r] , _wr[r] , multigraph, _bg);
+ Sf += eterm_dense(r, r, ers - deltap[r] - deltam[r] - deltal, _wr[r] - dwr, _wr[r] - dwr, multigraph, _bg);
+
+ Si += eterm_dense(r, nr, esnr , _wr[r] , _wr[nr] , multigraph, _bg);
+ Sf += eterm_dense(r, nr, esnr - deltap[nr] + deltam[r], _wr[r] - dwr, _wr[nr] + dwnr, multigraph, _bg);
+ }
+
+ if(s == nr)
+ {
+ Si += eterm_dense(nr, nr, esnr , _wr[nr] , _wr[nr] , multigraph, _bg);
+ Sf += eterm_dense(nr, nr, esnr + deltap[nr] + deltam[nr] + deltal, _wr[nr] + dwnr, _wr[nr] + dwnr, multigraph, _bg);
+
+ Si += eterm_dense(nr, r, esr , _wr[nr] , _wr[r] , multigraph, _bg);
+ Sf += eterm_dense(nr, r, esr + deltap[r] - deltam[nr], _wr[nr] + dwnr, _wr[r] - dwr, multigraph, _bg);
+ }
+ }
+ }
+
+ return Sf - Si + dS;
+ }
+
+ double virtual_move_dense(size_t v, size_t nr, bool multigraph)
+ {
+ return virtual_move_dense(v, nr, multigraph, _m_entries);
+ }
+
+ template
+ double virtual_move(size_t v, size_t nr, bool dense, bool multigraph,
+ bool partition_dl, bool deg_dl, bool edges_dl,
+ MEntries& m_entries)
+ {
+ size_t r = _b[v];
+
+ if (_bclabel[r] != _bclabel[nr])
+ return std::numeric_limits::infinity();
+
+ double dS;
+ if (dense)
+ dS = virtual_move_dense(v, nr, multigraph, m_entries);
+ else
+ dS = virtual_move_sparse(v, nr, m_entries);
+
+ if (partition_dl || deg_dl || edges_dl)
+ {
+ enable_partition_stats();
+ auto& ps = get_partition_stats(v);
+ if (partition_dl)
+ dS += ps.get_delta_dl(v, r, nr, _vweight);
+ if (_deg_corr && deg_dl)
+ dS += ps.get_delta_deg_dl(v, r, nr, _vweight, _eweight,
+ _degs, _g);
+ if (edges_dl)
+ dS += ps.get_delta_edges_dl(v, r, nr, _vweight, _g);
+ }
+
+ return dS;
+ }
+
+ double virtual_move(size_t v, size_t nr, bool dense, bool multigraph,
+ bool partition_dl, bool deg_dl, bool edges_dl)
+ {
+ return virtual_move(v, nr, dense, multigraph, partition_dl, deg_dl,
+ edges_dl, _m_entries);
+ }
+
+ double get_delta_dl(size_t v, size_t nr)
+ {
+ enable_partition_stats();
+ auto& ps = get_partition_stats(v);
+ return ps.get_delta_dl(v, _b[v], nr, _vweight);
+ }
+
+ // Sample node placement
+ template
+ size_t sample_block(size_t v, double c, vector& block_list,
+ RNG& rng)
+ {
+ // attempt random block
+ size_t s = uniform_sample(block_list, rng);
+
+ if (!std::isinf(c) && total_degreeS()(v, _g) > 0)
+ {
+ auto u = sample_neighbour(_neighbour_sampler[v], rng);
+ size_t t = _b[u];
+ double p_rand = 0;
+ if (c > 0)
+ {
+ size_t B = num_vertices(_bg);
+ if (is_directed::apply::type::value)
+ p_rand = c * B / double(_mrp[t] + _mrm[t] + c * B);
+ else
+ p_rand = c * B / double(_mrp[t] + c * B);
+ }
+
+ typedef std::uniform_real_distribution<> rdist_t;
+ if (c == 0 || rdist_t()(rng) >= p_rand)
+ {
+ if (_egroups.empty())
+ _egroups.init(_b, _eweight, _g, _bg);
+ const auto& e = _egroups.sample_edge(t, rng);
+ s = _b[target(e, _g)];
+ if (s == t)
+ s = _b[source(e, _g)];
+ }
+ }
+
+ return s;
+ }
+
+ size_t sample_block(size_t v, double c, vector& block_list,
+ rng_t& rng)
+ {
+ return sample_block(v, c, block_list, rng);
+ }
+
+
+ template
+ size_t random_neighbour(size_t v, RNG& rng)
+ {
+ if (_neighbour_sampler[v].size() == 0)
+ return v;
+ return sample_neighbour(_neighbour_sampler[v], rng);
+ }
+
+ // Computes the move proposal probability
+ template
+ double get_move_prob(size_t v, size_t r, size_t s, double c, bool reverse,
+ MEntries& m_entries)
+ {
+ typedef typename graph_traits::vertex_descriptor vertex_t;
+ size_t B = num_vertices(_bg);
+ double p = 0;
+ size_t w = 0;
+
+ size_t kout = out_degreeS()(v, _g, _eweight);
+ size_t kin = kout;
+ if (is_directed::apply::type::value)
+ kin = in_degreeS()(v, _g, _eweight);
+
+ for (auto e : all_edges_range(v, _g))
+ {
+ vertex_t u = target(e, _g);
+ if (is_directed::apply::type::value && u == v)
+ u = source(e, _g);
+ vertex_t t = _b[u];
+ if (u == v)
+ t = r;
+ size_t ew = _eweight[e];
+ w += ew;
+
+ int mts;
+ if (t == r && s == size_t(_b[u]))
+ mts = _mrs[_emat.get_bedge(e)];
+ else
+ mts = get_mrs(t, s, _mrs, _emat);
+ int mtp = _mrp[t];
+ int mst = mts;
+ int mtm = mtp;
+
+ if (is_directed::apply::type::value)
+ {
+ mst = get_mrs(s, t, _mrs, _emat);
+ mtm = _mrm[t];
+ }
+
+ if (reverse)
+ {
+ int dts = m_entries.get_delta(t, s);
+ int dst = dts;
+ if (is_directed::apply::type::value)
+ dst = m_entries.get_delta(s, t);
+
+ mts += dts;
+ mst += dst;
+
+ if (t == s)
+ {
+ mtp -= kout;
+ mtm -= kin;
+ }
+
+ if (t == r)
+ {
+ mtp += kout;
+ mtm += kin;
+ }
+ }
+
+ if (is_directed::apply::type::value)
+ {
+ p += ew * ((mts + mst + c) / (mtp + mtm + c * B));
+ }
+ else
+ {
+ if (t == s)
+ mts *= 2;
+ p += ew * (mts + c) / (mtp + c * B);
+ }
+ }
+ if (w > 0)
+ return p / w;
+ else
+ return 1. / B;
+ }
+
+ double get_move_prob(size_t v, size_t r, size_t s, double c, bool reverse)
+ {
+ return get_move_prob(v, r, s, c, reverse, _m_entries);
+ }
+
+ bool is_last(size_t v)
+ {
+ return _wr[_b[v]] == _vweight[v];
+ }
+
+ double get_deg_entropy(size_t v, const simple_degs_t&)
+ {
+ if (_ignore_degree[v] == 1)
+ return 0;
+ auto kin = in_degreeS()(v, _g);
+ auto kout = out_degreeS()(v, _g);
+ if (_ignore_degree[v] == 2)
+ kout = 0;
+ double S = -lgamma_fast(kin + 1) - lgamma_fast(kout + 1);
+ return S * _vweight[v];
+ }
+
+ double get_deg_entropy(size_t v, typename degs_map_t::unchecked_t& degs)
+ {
+ if (_ignore_degree[v] == 1)
+ return 0;
+ double S = 0;
+ for (auto& ks : degs[v])
+ {
+ auto kin = get<0>(ks);
+ auto kout = get<1>(ks);
+ if (_ignore_degree[v] == 2)
+ kout = 0;
+ int n = get<2>(ks);
+ S -= n * (lgamma_fast(kin + 1) + lgamma_fast(kout + 1));
+ }
+ return S;
+ }
+
+ double sparse_entropy(bool multigraph, bool deg_entropy)
+ {
+ double S = 0;
+ for (auto e : edges_range(_bg))
+ S += eterm(source(e, _bg), target(e, _bg), _mrs[e], _bg);
+ for (auto v : vertices_range(_bg))
+ S += vterm(_mrp[v], _mrm[v], _wr[v], _deg_corr, _bg);
+
+ if (_deg_corr && deg_entropy)
+ {
+ for (auto v : vertices_range(_g))
+ S += get_deg_entropy(v, _degs);
+ }
+
+ if (multigraph)
+ {
+ for (auto v : vertices_range(_g))
+ {
+ gt_hash_map us;
+ for (auto e : out_edges_range(v, _g))
+ {
+ auto u = target(e, _g);
+ if (u < v && !is_directed::apply::type::value)
+ continue;
+ us[u] += _eweight[e];
+ }
+
+ for (auto& uc : us)
+ {
+ auto& u = uc.first;
+ auto& m = uc.second;
+ if (m > 1)
+ {
+ if (u == v && !is_directed::apply::type::value)
+ {
+ assert(m % 2 == 0);
+ S += lgamma_fast(m/2 + 1);
+ }
+ else
+ {
+ S += lgamma_fast(m + 1);
+ }
+ }
+ }
+ }
+ }
+ return S;
+ }
+
+ double dense_entropy(bool multigraph)
+ {
+ if (_deg_corr)
+ throw GraphException("Dense entropy for degree corrected model not implemented!");
+ double S = 0;
+ for (auto e : edges_range(_bg))
+ {
+ auto r = source(e, _bg);
+ auto s = target(e, _bg);
+ S += eterm_dense(r, s, _mrs[e], _wr[r], _wr[s], multigraph, _bg);
+ }
+ return S;
+ }
+
+ double entropy(bool dense, bool multigraph, bool deg_entropy)
+ {
+ if (dense)
+ return dense_entropy(multigraph);
+ else
+ return sparse_entropy(multigraph, deg_entropy);
+ }
+
+ double get_partition_dl()
+ {
+ enable_partition_stats();
+ double S = 0;
+ for (auto& ps : _partition_stats)
+ S += ps.get_partition_dl();
+ return S;
+ }
+
+ double get_deg_dl(bool ent, bool dl_alt, bool xi_fast)
+ {
+ enable_partition_stats();
+ double S = 0;
+ for (auto& ps : _partition_stats)
+ S += ps.get_deg_dl(ent, dl_alt, xi_fast);
+ return S;
+ }
+
+ template
+ double get_parallel_neighbours_entropy(size_t v, Vlist& us)
+ {
+ double S = 0;
+ for (auto& uc : us)
+ {
+ auto& u = uc.first;
+ auto& m = uc.second;
+ if (m > 1)
+ {
+ if (u == v && !is_directed::apply::type::value)
+ {
+ assert(m % 2 == 0);
+ S += lgamma_fast(m/2 + 1);
+ }
+ else
+ {
+ S += lgamma_fast(m + 1);
+ }
+ }
+ }
+ return S;
+ }
+
+ double get_parallel_entropy()
+ {
+ double S = 0;
+ for (auto v : vertices_range(_g))
+ {
+ gt_hash_map us;
+ for (auto e : out_edges_range(v, _g))
+ {
+ auto u = target(e, _g);
+ if (u < v && !is_directed::apply::type::value)
+ continue;
+ us[u] += _eweight[e];
+ }
+ S += get_parallel_neighbours_entropy(v, us);
+ }
+ return S;
+ }
+
+ void enable_partition_stats()
+ {
+ if (_partition_stats.empty())
+ {
+ size_t E = 0;
+ for (auto e : edges_range(_g))
+ E += _eweight[e];
+ size_t B = 0;
+ for (auto r : vertices_range(_bg))
+ if (_wr[r] > 0)
+ B++;
+
+ auto vi = std::max_element(vertices(_g).first, vertices(_g).second,
+ [&](auto u, auto v)
+ { return (this->_pclabel[u] <
+ this->_pclabel[v]); });
+ size_t C = _pclabel[*vi] + 1;
+
+ vector> vcs(C);
+ vector rc(num_vertices(_bg));
+ for (auto v : vertices_range(_g))
+ {
+ vcs[_pclabel[v]].push_back(v);
+ rc[_b[v]] = _pclabel[v];
+ }
+
+ for (size_t c = 0; c < C; ++c)
+ _partition_stats.emplace_back(_g, _b, vcs[c], E, B,
+ _vweight, _eweight, _degs,
+ _ignore_degree, _bmap);
+
+ for (auto r : vertices_range(_bg))
+ _partition_stats[rc[r]].get_r(r);
+ }
+ }
+
+ void disable_partition_stats()
+ {
+ _partition_stats.clear();
+ }
+
+ bool is_partition_stats_enabled() const
+ {
+ return !_partition_stats.empty();
+ }
+
+ partition_stats_t& get_partition_stats(size_t v)
+ {
+ return _partition_stats[_pclabel[v]];
+ }
+
+ void init_mcmc(double c, double dl)
+ {
+ if (!std::isinf(c))
+ {
+ if (_egroups.empty())
+ _egroups.init(_b, _eweight, _g, _bg);
+ }
+ else
+ {
+ _egroups.clear();
+ }
+
+ if (dl)
+ enable_partition_stats();
+ else
+ disable_partition_stats();
+ }
+
+
+//private:
+ typedef typename
+ std::conditional::type::value,
+ GraphInterface::multigraph_t,
+ UndirectedAdaptor>::type
+ bg_t;
+ bg_t& _bg;
+
+ typename mrs_t::checked_t _c_mrs;
+
+ typedef typename std::conditional,
+ EMat>::type
+ emat_t;
+ emat_t _emat;
+
+ typedef typename is_constant_property::type is_weighted;
+ EGroups _egroups;
+
+ typedef typename std::conditional,
+ typename property_map::type>::type,
+ typename property_map_type::apply,
+ typename property_map::type>::type>::type::unchecked_t
+ sampler_map_t;
+
+ sampler_map_t _neighbour_sampler;
+ std::vector _partition_stats;
+ std::vector _bmap;
+
+ EntrySet _m_entries;
+};
+
+} // graph_tool namespace
+
+#endif //GRAPH_BLOCKMODEL_HH
diff --git a/src/graph/inference/graph_blockmodel_gibbs.cc b/src/graph/inference/graph_blockmodel_gibbs.cc
new file mode 100644
index 0000000000000000000000000000000000000000..8cf35ccdd496f6e7bf8a700ccb9249f04e4acdcc
--- /dev/null
+++ b/src/graph/inference/graph_blockmodel_gibbs.cc
@@ -0,0 +1,63 @@
+// graph-tool -- a general graph modification and manipulation thingy
+//
+// Copyright (C) 2006-2016 Tiago de Paula Peixoto
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// as published by the Free Software Foundation; either version 3
+// of the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program. If not, see .
+
+#include "graph_tool.hh"
+#include "random.hh"
+
+#include
+
+#include "graph_blockmodel_util.hh"
+#include "graph_blockmodel.hh"
+#include "graph_blockmodel_gibbs.hh"
+#include "gibbs_loop.hh"
+
+using namespace boost;
+using namespace graph_tool;
+
+GEN_DISPATCH(block_state, BlockState, BLOCK_STATE_params)
+
+template
+GEN_DISPATCH(gibbs_block_state, Gibbs::template GibbsBlockState,
+ GIBBS_BLOCK_STATE_params(State))
+
+python::object do_gibbs_sweep(python::object ogibbs_state,
+ python::object oblock_state,
+ rng_t& rng)
+{
+ python::object ret;
+ auto dispatch = [&](auto& block_state)
+ {
+ typedef typename std::remove_reference::type
+ state_t;
+
+ gibbs_block_state::make_dispatch
+ (ogibbs_state,
+ [&](auto& s)
+ {
+ auto ret_ = gibbs_sweep(s, rng);
+ ret = python::make_tuple(ret_.first, ret_.second);
+ });
+ };
+ block_state::dispatch(oblock_state, dispatch);
+ return ret;
+}
+
+void export_blockmodel_gibbs()
+{
+ using namespace boost::python;
+ def("gibbs_sweep", &do_gibbs_sweep);
+}
diff --git a/src/graph/inference/graph_blockmodel_gibbs.hh b/src/graph/inference/graph_blockmodel_gibbs.hh
new file mode 100644
index 0000000000000000000000000000000000000000..811fb30f4719cc1ecefd4bb14f9e6e9d986c432f
--- /dev/null
+++ b/src/graph/inference/graph_blockmodel_gibbs.hh
@@ -0,0 +1,209 @@
+// graph-tool -- a general graph modification and manipulation thingy
+//
+// Copyright (C) 2006-2016 Tiago de Paula Peixoto
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// as published by the Free Software Foundation; either version 3
+// of the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program. If not, see .
+
+#ifndef GRAPH_BLOCKMODEL_GIBBS_HH
+#define GRAPH_BLOCKMODEL_GIBBS_HH
+
+#include "config.h"
+
+#include
+
+#include "graph_tool.hh"
+#include "graph_state.hh"
+#include "graph_blockmodel_util.hh"
+#include
+
+namespace graph_tool
+{
+using namespace boost;
+using namespace std;
+
+#define GIBBS_BLOCK_STATE_params(State) \
+ ((__class__,&, mpl::vector, 1)) \
+ ((state, &, State&, 0)) \
+ ((E,, size_t, 0)) \
+ ((vlist,&, std::vector&, 0)) \
+ ((block_list,&, std::vector&, 0)) \
+ ((beta,, double, 0)) \
+ ((multigraph,, bool, 0)) \
+ ((dense,, bool, 0)) \
+ ((partition_dl,, bool, 0)) \
+ ((degree_dl,, bool, 0)) \
+ ((edges_dl,, bool, 0)) \
+ ((allow_empty,, bool, 0)) \
+ ((parallel,, bool, 0)) \
+ ((sequential,, bool, 0)) \
+ ((verbose,, bool, 0)) \
+ ((niter,, size_t, 0))
+
+
+template class MEntries = EntrySet>
+struct Gibbs
+{
+ GEN_STATE_BASE(GibbsBlockStateBase, GIBBS_BLOCK_STATE_params(State))
+
+ template
+ class GibbsBlockState
+ : public GibbsBlockStateBase
+ {
+ public:
+ GET_PARAMS_USING(GibbsBlockStateBase,
+ GIBBS_BLOCK_STATE_params(State))
+ GET_PARAMS_TYPEDEF(Ts, GIBBS_BLOCK_STATE_params(State))
+
+ template * = nullptr>
+ GibbsBlockState(ATs&&... as)
+ : GibbsBlockStateBase(as...),
+ _g(_state._g),
+ _m_entries(num_vertices(_state._bg)),
+ _B(num_vertices(_state._bg)),
+ _tglobal(std::make_shared())
+ {
+ _state.init_mcmc(numeric_limits::infinity(),
+ _partition_dl || _degree_dl || _edges_dl);
+
+ size_t C = 0;
+ for (auto v : vertices_range(_g))
+ C = std::max(C, _state._bclabel[_state._b[v]]);
+ C++;
+
+ auto& moves = _tglobal->moves;
+ auto& weights = _tglobal->weights;
+ auto& empty = _tglobal->empty;
+
+ empty.resize(C);
+
+ for(size_t c = 0; c < C; ++c)
+ {
+ moves.push_back(_B + c);
+ weights.push_back(0);
+ }
+
+ for (auto r : _block_list)
+ {
+ if (_state._wr[r] > 0)
+ {
+ moves.push_back(r);
+ weights.push_back(1);
+ }
+ else
+ {
+ auto c = _state._bclabel[r];
+ empty[c].push_back(r);
+ }
+ }
+
+ for (size_t c = 0; c < C; ++c)
+ weights[c] = empty[c].size();
+ }
+
+ typename state_t::g_t& _g;
+ MEntries _m_entries;
+
+ size_t _B;
+
+ struct tglobal_t
+ {
+ vector moves;
+ vector weights;
+ vector> empty;
+ };
+
+ std::shared_ptr _tglobal;
+
+ auto& get_moves(size_t) { return _tglobal->moves; }
+ auto& get_weights(size_t) { return _tglobal->weights; }
+
+ size_t node_state(size_t v)
+ {
+ return _state._b[v];
+ }
+
+ double virtual_move_dS(size_t v, size_t nr)
+ {
+ if (nr >= _B)
+ {
+ if (_allow_empty)
+ {
+ auto& empty = _tglobal->empty;
+ auto c = nr - _B;
+ if (empty[c].empty())
+ return numeric_limits::infinity();
+ nr = empty[c].back();
+ }
+ else
+ {
+ return numeric_limits::infinity();
+ }
+ }
+ size_t r = _state._b[v];
+ if (_state._bclabel[r] != _state._bclabel[nr])
+ return numeric_limits::infinity();
+ return _state.virtual_move(v, nr, _dense, _multigraph,
+ _partition_dl, _degree_dl, _edges_dl,
+ _m_entries);
+ }
+
+ void perform_move(size_t v, size_t nr)
+ {
+ size_t r = _state._b[v];
+
+ if (r == nr)
+ return;
+
+ auto& moves = _tglobal->moves;
+ auto& weights = _tglobal->weights;
+ auto& empty = _tglobal->empty;
+
+ if (nr >= _B)
+ {
+ auto c = nr - _B;
+ assert(!empty[c].empty());
+ nr = empty[c].back();
+ empty[c].pop_back();
+ weights[c]--;
+ moves.push_back(nr);
+ weights.push_back(1);
+ }
+
+ assert(_state._wr[r] > 0);
+
+ _state.move_vertex(v, nr);
+
+ if (_state._wr[r] == 0)
+ {
+ auto c = _state._bclabel[r];
+ empty[c].push_back(r);
+ weights[c]++;
+
+ auto iter = find(moves.begin(), moves.end(), r);
+ assert(iter != moves.end());
+ size_t pos = iter - moves.begin();
+ std::swap(moves[pos], moves.back());
+ moves.pop_back();
+ weights.pop_back();
+ }
+ }
+ };
+};
+
+
+} // graph_tool namespace
+
+#endif //GRAPH_BLOCKMODEL_GIBBS_HH
diff --git a/src/graph/inference/graph_blockmodel_layers.cc b/src/graph/inference/graph_blockmodel_layers.cc
new file mode 100644
index 0000000000000000000000000000000000000000..218efa3a81e5197394cfc392e575aa2c6e8b0d11
--- /dev/null
+++ b/src/graph/inference/graph_blockmodel_layers.cc
@@ -0,0 +1,495 @@
+// graph-tool -- a general graph modification and manipulation thingy
+//
+// Copyright (C) 2006-2016 Tiago de Paula Peixoto
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// as published by the Free Software Foundation; either version 3
+// of the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program. If not, see .
+
+#include "graph_tool.hh"
+#include "random.hh"
+
+#include
+
+#include "graph_blockmodel_util.hh"
+#include "graph_blockmodel.hh"
+#include "graph_blockmodel_layers_util.hh"
+#define BASE_STATE_params BLOCK_STATE_params
+#include "graph_blockmodel_layers.hh"
+#include "graph_state.hh"
+
+using namespace boost;
+using namespace graph_tool;
+
+GEN_DISPATCH(block_state, BlockState, BLOCK_STATE_params)
+
+template
+GEN_DISPATCH(layered_block_state, Layers::template LayeredBlockState,
+ LAYERED_BLOCK_STATE_params)
+
+python::object make_layered_block_state(boost::python::object oblock_state,
+ boost::python::object olayered_state)
+{
+ python::object state;
+ auto dispatch = [&](auto& block_state)
+ {
+ typedef typename std::remove_reference::type
+ state_t;
+
+ layered_block_state::make_dispatch
+ (olayered_state,
+ [&](auto& s)
+ {
+ state = python::object(s);
+ },
+ block_state);
+ };
+ block_state::dispatch(oblock_state, dispatch);
+ return state;
+}
+
+template
+vector from_list(boost::python::object list)
+{
+ vector v;
+ for (int i = 0; i < boost::python::len(list); ++i)
+ v.push_back(boost::python::extract(list[i])());
+ return v;
+};
+
+template
+vector> from_rlist(boost::python::object list)
+{
+ vector> v;
+ for (int i = 0; i < boost::python::len(list); ++i)
+ v.emplace_back(boost::python::extract(list[i])());
+ return v;
+};
+
+template
+vector