[med-svn] [Git][med-team/python-leidenalg][master] 5 commits: New upstream version 0.8.6
Nilesh Patra (@nilesh)
gitlab at salsa.debian.org
Sat Jul 3 15:01:46 BST 2021
Nilesh Patra pushed to branch master at Debian Med / python-leidenalg
Commits:
47869354 by Nilesh Patra at 2021-07-03T19:03:00+05:30
New upstream version 0.8.6
- - - - -
b5d3a03a by Nilesh Patra at 2021-07-03T19:03:03+05:30
Update upstream source from tag 'upstream/0.8.6'
Update to upstream version '0.8.6'
with Debian dir 6aeb293a61121a59ddc0152fee2445bb18d47926
- - - - -
9abc669c by Nilesh Patra at 2021-07-03T19:22:46+05:30
d/rules: Specify IGRAPH_EXTRA_INCLUDE_PATH for setup.py to pick up env variable
- - - - -
557c411f by Nilesh Patra at 2021-07-03T19:27:22+05:30
d/tests/run-unit-test: Do not run autopkgtests in project root
- - - - -
6961a5fd by Nilesh Patra at 2021-07-03T19:28:41+05:30
Upload to unstable
- - - - -
21 changed files:
- .github/workflows/build.yml
- CHANGELOG
- README.rst
- build-doc.yml
- debian/changelog
- debian/rules
- debian/tests/run-unit-test
- include/pynterface.h
- include/python_optimiser_interface.h
- include/python_partition_interface.h
- setup.py
- src/leidenalg/MutableVertexPartition.cpp
- src/leidenalg/Optimiser.cpp
- src/leidenalg/Optimiser.py
- src/leidenalg/SignificanceVertexPartition.cpp
- src/leidenalg/VertexPartition.py
- src/leidenalg/functions.py
- src/leidenalg/python_optimiser_interface.cpp
- src/leidenalg/python_partition_interface.cpp
- tests/test_Optimiser.py
- tests/test_VertexPartition.py
Changes:
=====================================
.github/workflows/build.yml
=====================================
@@ -8,9 +8,10 @@ on:
branches:
- master
+
env:
CIBW_TEST_REQUIRES: ddt
- CIBW_TEST_COMMAND: "cd {project} && python -m unittest"
+ CIBW_TEST_COMMAND: "cd {project} && python -m unittest -v"
CIBW_SKIP: "cp27-* pp27-* cp35-*"
jobs:
@@ -119,7 +120,7 @@ jobs:
CIBW_BEFORE_BUILD: "python setup.py build_c_core"
CIBW_BUILD: "*-${{ matrix.wheel_arch }}"
IGRAPH_CMAKE_EXTRA_ARGS: -DCMAKE_BUILD_TYPE=Release -A ${{ matrix.cmake_arch }}
- CIBW_TEST_COMMAND: "cd /d {project} && python -m unittest"
+ CIBW_TEST_COMMAND: "cd /d {project} && python -m unittest -v"
- uses: actions/upload-artifact at v2
with:
@@ -163,7 +164,7 @@ jobs:
- name: Test
run: |
pip install ddt
- python -m unittest
+ python -m unittest -v
- uses: actions/upload-artifact at v2
with:
@@ -174,7 +175,6 @@ jobs:
runs-on: ubuntu-latest
# upload to PyPI on every push from the master branch
if: github.event_name == 'push' &&
- github.ref == 'refs/heads/master' &&
startsWith(github.ref, 'refs/tags')
steps:
- uses: actions/download-artifact at v2
=====================================
CHANGELOG
=====================================
@@ -1,3 +1,11 @@
+0.8.6
+- Removed accidentally left DEBUG statement
+
+0.8.5
+- Corrected iterating over nodes (PR #70).
+- Fixed segfault with move_nodes_constrained (issue #68)
+- Fixed problem with initial_membership (issue #66)
+
0.8.4
- Update C core to 0.9.1
- Fixed caching problem (issue #62)
=====================================
README.rst
=====================================
@@ -18,13 +18,14 @@ assignments remain fixed [10]_. It also provides some support for community
detection on bipartite graphs. See the `documentation
<http://leidenalg.readthedocs.io/en/latest/>`_ for more information.
+
.. image:: https://readthedocs.org/projects/leidenalg/badge
:target: http://leidenalg.readthedocs.io/en/latest/
:alt: Leiden documentation status
-.. image:: https://ci.appveyor.com/api/projects/status/26au75vj8iwq32qp?svg=true
- :target: https://ci.appveyor.com/project/vtraag/leidenalg
- :alt: Leiden build status (AppVeyor)
+.. image:: https://github.com/vtraag/leidenalg/actions/workflows/build.yml/badge.svg?branch=master
+ :target: https://github.com/vtraag/leidenalg/actions/workflows/build.yml
+ :alt: Leiden build status (GitHub Actions)
.. image:: https://zenodo.org/badge/146722095.svg
:target: https://zenodo.org/badge/latestdoi/146722095
@@ -38,7 +39,7 @@ Installation
------------
In short: ``pip install leidenalg``. All major platforms are supported on
-Python>=3.5, earlier versions of Python are no longer supported. Alternatively,
+Python>=3.6, earlier versions of Python are no longer supported. Alternatively,
you can install from Anaconda (channel ``conda-forge``).
For Unix like systems it is possible to install from source. For Windows this is
@@ -84,9 +85,18 @@ sure to then install the ``C`` core library from source before. Make sure you
Usage
-----
-There is no standalone version of ``leidenalg``, and you will always need
-python to access it. There are no plans for developing a standalone version or
-R support. So, use python. Please refer to the documentation for more details
+There is no standalone version of ``leidenalg``, and you will always need python
+to access it. There are no plans at the moment for developing a standalone
+version or R support. However, there have been various efforts to port the
+package to R. These typically do not offer all available functionality or have
+some other limitations, but nonetheless may be very useful. The available ports
+are:
+
+- https://github.com/cole-trapnell-lab/leidenbase
+- https://github.com/TomKellyGenetics/leiden
+- https://github.com/kharchenkolab/leidenAlg
+
+Please refer to the documentation for more details
on function calls and parameters.
This implementation is made for flexibility, but ``igraph`` nowadays also
=====================================
build-doc.yml
=====================================
@@ -11,4 +11,5 @@ dependencies:
- automake
- flex
- bison
- - libtool
\ No newline at end of file
+ - libtool
+ - cmake
\ No newline at end of file
=====================================
debian/changelog
=====================================
@@ -1,3 +1,12 @@
+python-leidenalg (0.8.6-1) unstable; urgency=medium
+
+ * New upstream version 0.8.6
+ * d/rules: Specify IGRAPH_EXTRA_INCLUDE_PATH
+ for setup.py to pick up env variable
+ * d/tests/run-unit-test: Do not run autopkgtests in project root
+
+ -- Nilesh Patra <nilesh at debian.org> Sat, 03 Jul 2021 19:28:17 +0530
+
python-leidenalg (0.8.4-2) unstable; urgency=medium
[ Shruti Sridhar ]
=====================================
debian/rules
=====================================
@@ -5,6 +5,7 @@ DH_VERBOSE := 1
export PYBUILD_NAME=leidenalg
export DEB_BUILD_MAINT_OPTIONS=hardening=+all
+export IGRAPH_EXTRA_INCLUDE_PATH=/usr/include/igraph
%:
dh $@ --with python3 --buildsystem=pybuild
=====================================
debian/tests/run-unit-test
=====================================
@@ -1,7 +1,17 @@
#!/bin/bash
set -e
-for py in $(py3versions -r 2> /dev/null)
+CUR_DIR=`pwd`
+if [ "$AUTOPKGTEST_TMP" = "" ] ; then
+ AUTOPKGTEST_TMP=`mktemp -d /tmp/${pkg}-test.XXXXXX`
+ trap "rm -rf $AUTOPKGTEST_TMP" 0 INT QUIT ABRT PIPE TERM
+fi
+
+cp -a ${CUR_DIR}/tests/ $AUTOPKGTEST_TMP
+
+cd $AUTOPKGTEST_TMP
+
+for py in $(py3versions -s 2> /dev/null)
do
$py -m pytest -v
=====================================
include/pynterface.h
=====================================
@@ -1,10 +1,6 @@
#ifndef PYNTERFACE_H_INCLUDED
#define PYNTERFACE_H_INCLUDED
-#if PY_MAJOR_VERSION >= 3
-#define IS_PY3K
-#endif
-
#include <Python.h>
#include <igraph.h>
#include "GraphHelper.h"
@@ -90,14 +86,7 @@ extern "C"
PyObject *error;
};
- #if PY_MAJOR_VERSION >= 3
#define GETSTATE(m) ((struct module_state*)PyModule_GetState(m))
- #else
- #define GETSTATE(m) (&_state)
- static struct module_state _state;
- #endif
-
- #if PY_MAJOR_VERSION >= 3
static int leiden_traverse(PyObject *m, visitproc visit, void *arg) {
Py_VISIT(GETSTATE(m)->error);
@@ -125,19 +114,8 @@ extern "C"
PyObject *
PyInit__c_leiden(void)
-
- #else
- #define INITERROR return
-
- void
- init_c_leiden(void)
- #endif
{
- #if PY_MAJOR_VERSION >= 3
PyObject* module = PyModule_Create(&leidendef);
- #else
- PyObject *module = Py_InitModule3("_c_leiden", leiden_funcs, "Leiden extension using igraph.");
- #endif
PyModule_AddIntConstant(module, "ALL_COMMS", Optimiser::ALL_COMMS);
PyModule_AddIntConstant(module, "ALL_NEIGH_COMMS", Optimiser::ALL_NEIGH_COMMS);
@@ -157,9 +135,7 @@ extern "C"
INITERROR;
}
- #if PY_MAJOR_VERSION >= 3
return module;
- #endif
}
#ifdef __cplusplus
=====================================
include/python_optimiser_interface.h
=====================================
@@ -1,10 +1,6 @@
#ifndef PYNTERFACE_OPTIMISER_H_INCLUDED
#define PYNTERFACE_OPTIMISER_H_INCLUDED
-#if PY_MAJOR_VERSION >= 3
-#define IS_PY3K
-#endif
-
#include <Python.h>
#include <igraph.h>
#include "GraphHelper.h"
=====================================
include/python_partition_interface.h
=====================================
@@ -1,10 +1,6 @@
#ifndef PYNTERFACE_PARTITION_H_INCLUDED
#define PYNTERFACE_PARTITION_H_INCLUDED
-#if PY_MAJOR_VERSION >= 3
-#define IS_PY3K
-#endif
-
#include <Python.h>
#include <igraph.h>
#include "GraphHelper.h"
@@ -31,6 +27,8 @@ Graph* create_graph_from_py(PyObject* py_obj_graph, PyObject* py_node_sizes);
Graph* create_graph_from_py(PyObject* py_obj_graph, PyObject* py_node_sizes, PyObject* py_weights);
Graph* create_graph_from_py(PyObject* py_obj_graph, PyObject* py_node_sizes, PyObject* py_weights, int check_positive_weight);
+vector<size_t> create_size_t_vector(PyObject* py_list);
+
PyObject* capsule_MutableVertexPartition(MutableVertexPartition* partition);
MutableVertexPartition* decapsule_MutableVertexPartition(PyObject* py_partition);
=====================================
setup.py
=====================================
@@ -35,13 +35,6 @@ from time import sleep
###########################################################################
-LIBIGRAPH_FALLBACK_INCLUDE_DIRS = ["/usr/include/igraph", "/usr/local/include/igraph"]
-LIBIGRAPH_FALLBACK_LIBRARIES = ["igraph"]
-LIBIGRAPH_FALLBACK_LIBRARY_DIRS = []
-
-###########################################################################
-
-
is_windows = platform.system() == "windows"
@@ -300,6 +293,7 @@ class BuildConfiguration(object):
self.define_macros = []
self.extra_objects = []
self.static_extension = False
+ self.external = False
self.use_pkgconfig = False
self._has_pkgconfig = None
self.excluded_include_dirs = []
@@ -369,13 +363,16 @@ class BuildConfiguration(object):
# Check whether the user asked us to discover a pre-built igraph
# with pkg-config
detected = False
- if buildcfg.use_pkgconfig:
- detected = buildcfg.detect_from_pkgconfig()
- if not detected:
- print(
- "Cannot find the C core of igraph on this system using pkg-config."
- )
- sys.exit(1)
+ if buildcfg.external:
+ if buildcfg.use_pkgconfig:
+ detected = buildcfg.detect_from_pkgconfig()
+ if not detected:
+ print(
+ "Cannot find the C core of igraph on this system using pkg-config."
+ )
+ sys.exit(1)
+ else:
+ buildcfg.use_educated_guess()
else:
# Build the C core from the vendored igraph source
self.run_command("build_c_core")
@@ -384,6 +381,14 @@ class BuildConfiguration(object):
if not detected:
buildcfg.use_educated_guess()
+ # Add any extra include paths if needed; this is needed for the
+ # Appveyor CI build
+ if "IGRAPH_EXTRA_INCLUDE_PATH" in os.environ:
+ buildcfg.include_dirs = (
+ list(os.environ["IGRAPH_EXTRA_INCLUDE_PATH"].split(os.pathsep))
+ + buildcfg.include_dirs
+ )
+
# Add any extra library paths if needed; this is needed for the
# Appveyor CI build
if "IGRAPH_EXTRA_LIBRARY_PATH" in os.environ:
@@ -649,6 +654,9 @@ class BuildConfiguration(object):
elif option == "--no-wait":
opts_to_remove.append(idx)
self.wait = False
+ elif option == "--external":
+ opts_to_remove.append(idx)
+ self.external = True
elif option == "--use-pkg-config":
opts_to_remove.append(idx)
self.use_pkgconfig = True
@@ -709,34 +717,25 @@ class BuildConfiguration(object):
buildcfg.libraries = eval(buildcfg_file.open("r").read())
def use_educated_guess(self):
- """Tries to guess the proper library names, include and library paths
- if everything else failed."""
-
- global LIBIGRAPH_FALLBACK_LIBRARIES
- global LIBIGRAPH_FALLBACK_INCLUDE_DIRS
- global LIBIGRAPH_FALLBACK_LIBRARY_DIRS
-
- print("WARNING: we were not able to detect where igraph is installed on")
- print("your machine (if it is installed at all). We will use the fallback")
- print("library and include paths hardcoded in setup.py and hope that the")
- print("C core of igraph is installed there.")
- print("")
- print("If the compilation fails and you are sure that igraph is installed")
- print("on your machine, adjust the following two variables in setup.py")
- print("accordingly and try again:")
- print("")
- print("- LIBIGRAPH_FALLBACK_INCLUDE_DIRS")
- print("- LIBIGRAPH_FALLBACK_LIBRARY_DIRS")
- print("")
-
- if self.wait:
- wait_for_keypress(seconds=10)
-
- self.libraries = LIBIGRAPH_FALLBACK_LIBRARIES[:]
- if self.static_extension:
- self.libraries.extend(["xml2", "z", "m", "stdc++"])
- self.include_dirs = LIBIGRAPH_FALLBACK_INCLUDE_DIRS[:]
- self.library_dirs = LIBIGRAPH_FALLBACK_LIBRARY_DIRS[:]
+ """Tries to guess the proper library names, include and library paths."""
+
+ print("""WARNING: You are trying to install with an external igraph library.
+No include dirs or library dirs are specified, so they need to be set externally.
+If compilation fails you may adjust the following environment variables to adjust
+the required paths.
+- IGRAPH_EXTRA_INCLUDE_PATH
+- IGRAPH_EXTRA_LIBRARY_PATH
+- IGRAPH_EXTRA_LIBRARIES
+- IGRAPH_EXTRA_DYNAMIC_LIBRARIES
+
+If a static build extension is used, we try to statically link to igraph. The extra
+libraries that are specified are then also assumed to be statically linked. If, in
+addition, some libraries need to be explicitly dynamically linked, you can specify this.
+ """)
+
+ self.libraries = ['igraph']
+ self.include_dirs = []
+ self.library_dirs = []
###########################################################################
=====================================
src/leidenalg/MutableVertexPartition.cpp
=====================================
@@ -373,7 +373,7 @@ vector<size_t> MutableVertexPartition::rank_order_communities(vector<MutableVert
#ifdef DEBUG
size_t n = partitions[0]->graph->vcount();
- for (size_t layer; layer < nb_layers; layer++)
+ for (size_t layer = 0; layer < nb_layers; layer++)
{
for (size_t v = 0; v < n; v++)
{
=====================================
src/leidenalg/Optimiser.cpp
=====================================
@@ -31,7 +31,7 @@ Optimiser::Optimiser()
this->max_comm_size = 0;
igraph_rng_init(&rng, &igraph_rngtype_mt19937);
- igraph_rng_seed(&rng, rand());
+ igraph_rng_seed(&rng, time(NULL));
}
Optimiser::~Optimiser()
@@ -563,8 +563,6 @@ double Optimiser::move_nodes(vector<MutableVertexPartition*> partitions, vector<
{
size_t v = vertex_order.front(); vertex_order.pop_front();
- Graph* graph = NULL;
- MutableVertexPartition* partition = NULL;
// What is the current community of the node (this should be the same for all layers)
size_t v_comm = partitions[0]->membership(v);
@@ -623,17 +621,15 @@ double Optimiser::move_nodes(vector<MutableVertexPartition*> partitions, vector<
// Check if we should move to an empty community
if (consider_empty_community)
{
- graph = graphs[0];
- partition = partitions[0];
- if ( partition->cnodes(v_comm) > 1 ) // We should not move a node when it is already in its own empty community (this may otherwise create more empty communities than nodes)
+ if ( partitions[0]->cnodes(v_comm) > 1 ) // We should not move a node when it is already in its own empty community (this may otherwise create more empty communities than nodes)
{
- size_t n_comms = partition->n_communities();
- size_t comm = partition->get_empty_community();
+ size_t n_comms = partitions[0]->n_communities();
+ size_t comm = partitions[0]->get_empty_community();
#ifdef DEBUG
- cerr << "Checking empty community (" << comm << ") for partition " << partition << endl;
+ cerr << "Checking empty community (" << comm << ") for partition " << partitions[0] << endl;
#endif
comms.push_back(comm);
- if (partition->n_communities() > n_comms)
+ if (partitions[0]->n_communities() > n_comms)
{
// If the empty community has just been added, we need to make sure
// that is has also been added to the other layers
@@ -726,15 +722,18 @@ double Optimiser::move_nodes(vector<MutableVertexPartition*> partitions, vector<
#endif
// Mark neighbours as unstable (if not in new community and not fixed)
- for (size_t u : graph->get_neighbours(v, IGRAPH_ALL))
+ for (Graph* graph : graphs)
{
- // If the neighbour was stable and is not in the new community, we
- // should mark it as unstable, and add it to the queue, skipping
- // fixed nodes
- if (is_node_stable[u] && partition->membership(v) != max_comm && !is_membership_fixed[u])
+ for (size_t u : graph->get_neighbours(v, IGRAPH_ALL))
{
- vertex_order.push_back(u);
- is_node_stable[u] = false;
+ // If the neighbour was stable and is not in the new community, we
+ // should mark it as unstable, and add it to the queue, skipping
+ // fixed nodes
+ if (is_node_stable[u] && partitions[0]->membership(u) != max_comm && !is_membership_fixed[u])
+ {
+ vertex_order.push_back(u);
+ is_node_stable[u] = false;
+ }
}
}
// Keep track of number of moves
@@ -1050,8 +1049,6 @@ double Optimiser::move_nodes_constrained(vector<MutableVertexPartition*> partiti
comm_added[comm] = false;
comms.clear();
- Graph* graph = NULL;
- MutableVertexPartition* partition = NULL;
// What is the current community of the node (this should be the same for all layers)
size_t v_comm = partitions[0]->membership(v);
@@ -1192,15 +1189,19 @@ double Optimiser::move_nodes_constrained(vector<MutableVertexPartition*> partiti
}
#endif
- // Mark neighbours as unstable (if not in new community)
- for (size_t u : graph->get_neighbours(v, IGRAPH_ALL))
+ // Mark neighbours as unstable (if not in new community and not fixed)
+ for (Graph* graph : graphs)
{
- // If the neighbour was stable and is not in the new community, we
- // should mark it as unstable, and add it to the queue
- if (is_node_stable[u] && partition->membership(v) != max_comm)
+ for (size_t u : graph->get_neighbours(v, IGRAPH_ALL))
{
- vertex_order.push_back(u);
- is_node_stable[u] = false;
+ // If the neighbour was stable and is not in the new community, we
+ // should mark it as unstable, and add it to the queue, skipping
+ // fixed nodes
+ if (is_node_stable[u] && partitions[0]->membership(u) != max_comm && constrained_partition->membership(u) == constrained_partition->membership(v))
+ {
+ vertex_order.push_back(u);
+ is_node_stable[u] = false;
+ }
}
}
=====================================
src/leidenalg/Optimiser.py
=====================================
@@ -2,10 +2,6 @@ from . import _c_leiden
from .VertexPartition import LinearResolutionParameterVertexPartition
from collections import namedtuple
from math import log, sqrt
-import sys
-
-# Check if working with Python 3
-PY3 = (sys.version > '3')
class Optimiser(object):
""" Class for doing community detection using the Leiden algorithm.
=====================================
src/leidenalg/SignificanceVertexPartition.cpp
=====================================
@@ -110,8 +110,12 @@ double SignificanceVertexPartition::diff_move(size_t v, size_t new_comm)
// Calculate actual diff
- diff = (double)N_oldx*KLL(q_oldx, p) + (double)N_newx*KLL(q_newx, p)
- - (double)N_old *KLL(q_old, p) - (double)N_new *KLL(q_new, p);
+ if (N_oldx != N_new || q_oldx != q_new)
+ diff += (double)N_oldx*KLL(q_oldx, p) - (double)N_new*KLL(q_new, p);
+
+ if (N_newx != N_old || q_newx != q_old)
+ diff += (double)N_newx*KLL(q_newx, p) - (double)N_old*KLL(q_old, p);
+
#ifdef DEBUG
cerr << "\t" << "diff: " << diff << "." << endl;
#endif
=====================================
src/leidenalg/VertexPartition.py
=====================================
@@ -1,9 +1,6 @@
import igraph as _ig
from . import _c_leiden
from .functions import _get_py_capsule
-import sys
-# Check if working with Python 3
-PY3 = (sys.version > '3')
class MutableVertexPartition(_ig.VertexClustering):
""" Contains a partition of graph, derives from :class:`ig.VertexClustering`.
=====================================
src/leidenalg/functions.py
=====================================
@@ -11,14 +11,9 @@ from ._c_leiden import MERGE_NODES
from collections import Counter
-# Check if working with Python 3
-PY3 = (sys.version > '3')
def _get_py_capsule(graph):
- if PY3:
- return graph.__graph_as_capsule()
- else:
- return graph.__graph_as_cobject()
+ return graph.__graph_as_capsule()
from .VertexPartition import *
from .Optimiser import *
=====================================
src/leidenalg/python_optimiser_interface.cpp
=====================================
@@ -404,11 +404,11 @@ extern "C"
#endif
#ifdef DEBUG
- cerr << "Capsule constrained partition at address " << py_partition << endl;
+ cerr << "Capsule constrained partition at address " << py_constrained_partition << endl;
#endif
MutableVertexPartition* constrained_partition = decapsule_MutableVertexPartition(py_constrained_partition);
#ifdef DEBUG
- cerr << "Using constrained partition at address " << partition << endl;
+ cerr << "Using constrained partition at address " << constrained_partition << endl;
#endif
if (consider_comms < 0)
@@ -545,11 +545,7 @@ extern "C"
cerr << "Using optimiser at address " << optimiser << endl;
#endif
- #ifdef IS_PY3K
return PyLong_FromLong(optimiser->consider_comms);
- #else
- return PyInt_FromLong(optimiser->consider_comms);
- #endif
}
PyObject* _Optimiser_set_refine_consider_comms(PyObject *self, PyObject *args, PyObject *keywds)
@@ -609,11 +605,7 @@ extern "C"
cerr << "Using optimiser at address " << optimiser << endl;
#endif
- #ifdef IS_PY3K
return PyLong_FromLong(optimiser->refine_consider_comms);
- #else
- return PyInt_FromLong(optimiser->refine_consider_comms);
- #endif
}
PyObject* _Optimiser_set_optimise_routine(PyObject *self, PyObject *args, PyObject *keywds)
@@ -673,11 +665,7 @@ extern "C"
cerr << "Using optimiser at address " << optimiser << endl;
#endif
- #ifdef IS_PY3K
return PyLong_FromLong(optimiser->optimise_routine);
- #else
- return PyInt_FromLong(optimiser->optimise_routine);
- #endif
}
PyObject* _Optimiser_set_refine_routine(PyObject *self, PyObject *args, PyObject *keywds)
@@ -737,11 +725,7 @@ extern "C"
cerr << "Using optimiser at address " << optimiser << endl;
#endif
- #ifdef IS_PY3K
return PyLong_FromLong(optimiser->refine_routine);
- #else
- return PyInt_FromLong(optimiser->refine_routine);
- #endif
}
PyObject* _Optimiser_set_consider_empty_community(PyObject *self, PyObject *args, PyObject *keywds)
=====================================
src/leidenalg/python_partition_interface.cpp
=====================================
@@ -1,9 +1,5 @@
#include "python_partition_interface.h"
-#if PY_MAJOR_VERSION >= 3
-#define IS_PY3K
-#endif
-
Graph* create_graph_from_py(PyObject* py_obj_graph, PyObject* py_node_sizes)
{
return create_graph_from_py(py_obj_graph, py_node_sizes, NULL, true);
@@ -20,11 +16,7 @@ Graph* create_graph_from_py(PyObject* py_obj_graph, PyObject* py_node_sizes, PyO
cerr << "create_graph_from_py" << endl;
#endif
- #ifdef IS_PY3K
- igraph_t* py_graph = (igraph_t*) PyCapsule_GetPointer(py_obj_graph, NULL);
- #else
- igraph_t* py_graph = (igraph_t*) PyCObject_AsVoidPtr(py_obj_graph);
- #endif
+ igraph_t* py_graph = (igraph_t*) PyCapsule_GetPointer(py_obj_graph, NULL);
#ifdef DEBUG
cerr << "Got igraph_t " << py_graph << endl;
#endif
@@ -55,13 +47,10 @@ Graph* create_graph_from_py(PyObject* py_obj_graph, PyObject* py_node_sizes, PyO
for (size_t v = 0; v < n; v++)
{
PyObject* py_item = PyList_GetItem(py_node_sizes, v);
- #ifdef IS_PY3K
- if (PyLong_Check(py_item))
- #else
- if (PyInt_Check(py_item) || PyLong_Check(py_item))
- #endif
+ if (PyNumber_Check(py_item) && PyIndex_Check(py_item))
{
- node_sizes[v] = PyLong_AsLong(py_item);
+ size_t e = PyLong_AsSize_t(PyNumber_Long(py_item));
+ node_sizes[v] = e;
}
else
{
@@ -135,6 +124,27 @@ Graph* create_graph_from_py(PyObject* py_obj_graph, PyObject* py_node_sizes, PyO
return graph;
}
+vector<size_t> create_size_t_vector(PyObject* py_list)
+{
+ size_t n = PyList_Size(py_list);
+ vector<size_t> result(n);
+ for (size_t i = 0; i < n; i++)
+ {
+ PyObject* py_item = PyList_GetItem(py_list, i);
+ if (PyNumber_Check(py_item) && PyIndex_Check(py_item))
+ {
+ size_t e = PyLong_AsSize_t(PyNumber_Long(py_item));
+ if (e >= n)
+ throw Exception("Value cannot exceed length of list.");
+ else
+ result[i] = e;
+ }
+ else
+ throw Exception("Value cannot exceed length of list.");
+ }
+ return result;
+}
+
PyObject* capsule_MutableVertexPartition(MutableVertexPartition* partition)
{
PyObject* py_partition = PyCapsule_New(partition, "leidenalg.VertexPartition.MutableVertexPartition", del_MutableVertexPartition);
@@ -180,34 +190,7 @@ extern "C"
// If necessary create an initial partition
if (py_initial_membership != NULL && py_initial_membership != Py_None)
{
-
- vector<size_t> initial_membership;
-
- #ifdef DEBUG
- cerr << "Reading initial membership." << endl;
- #endif
- size_t n = PyList_Size(py_initial_membership);
- initial_membership.resize(n);
- for (size_t v = 0; v < n; v++)
- {
- PyObject* py_item = PyList_GetItem(py_initial_membership, v);
- if (PyNumber_Check(py_item) && PyIndex_Check(py_item))
- {
- size_t m = PyLong_AsSize_t(py_item);
- if (m >= n)
- {
- PyErr_SetString(PyExc_TypeError, "Membership cannot exceed number of nodes.");
- return NULL;
- }
- else
- initial_membership[v] = m;
- }
- else
- {
- PyErr_SetString(PyExc_TypeError, "Expected integer value for membership vector.");
- return NULL;
- }
- }
+ vector<size_t> initial_membership = create_size_t_vector(py_initial_membership);
partition = new ModularityVertexPartition(graph, initial_membership);
}
@@ -255,34 +238,7 @@ extern "C"
// If necessary create an initial partition
if (py_initial_membership != NULL && py_initial_membership != Py_None)
{
-
- vector<size_t> initial_membership;
-
- #ifdef DEBUG
- cerr << "Reading initial membership." << endl;
- #endif
- size_t n = PyList_Size(py_initial_membership);
- initial_membership.resize(n);
- for (size_t v = 0; v < n; v++)
- {
- PyObject* py_item = PyList_GetItem(py_initial_membership, v);
- if (PyNumber_Check(py_item) && PyIndex_Check(py_item))
- {
- size_t m = PyLong_AsSize_t(py_item);
- if (m >= n)
- {
- PyErr_SetString(PyExc_TypeError, "Membership cannot exceed number of nodes.");
- return NULL;
- }
- else
- initial_membership[v] = m;
- }
- else
- {
- PyErr_SetString(PyExc_TypeError, "Expected integer value for membership vector.");
- return NULL;
- }
- }
+ vector<size_t> initial_membership = create_size_t_vector(py_initial_membership);
partition = new SignificanceVertexPartition(graph, initial_membership);
}
@@ -330,34 +286,7 @@ extern "C"
// If necessary create an initial partition
if (py_initial_membership != NULL && py_initial_membership != Py_None)
{
-
- vector<size_t> initial_membership;
-
- #ifdef DEBUG
- cerr << "Reading initial membership." << endl;
- #endif
- size_t n = PyList_Size(py_initial_membership);
- initial_membership.resize(n);
- for (size_t v = 0; v < n; v++)
- {
- PyObject* py_item = PyList_GetItem(py_initial_membership, v);
- if (PyNumber_Check(py_item) && PyIndex_Check(py_item))
- {
- size_t m = PyLong_AsSize_t(py_item);
- if (m >= n)
- {
- PyErr_SetString(PyExc_TypeError, "Membership cannot exceed number of nodes.");
- return NULL;
- }
- else
- initial_membership[v] = m;
- }
- else
- {
- PyErr_SetString(PyExc_TypeError, "Expected integer value for membership vector.");
- return NULL;
- }
- }
+ vector<size_t> initial_membership = create_size_t_vector(py_initial_membership);
partition = new SurpriseVertexPartition(graph, initial_membership);
}
@@ -406,37 +335,7 @@ extern "C"
// If necessary create an initial partition
if (py_initial_membership != NULL && py_initial_membership != Py_None)
{
-
- vector<size_t> initial_membership;
-
- #ifdef DEBUG
- cerr << "Reading initial membership." << endl;
- #endif
- size_t n = PyList_Size(py_initial_membership);
- #ifdef DEBUG
- cerr << "Size " << n << endl;
- #endif
- initial_membership.resize(n);
- for (size_t v = 0; v < n; v++)
- {
- PyObject* py_item = PyList_GetItem(py_initial_membership, v);
- if (PyNumber_Check(py_item) && PyIndex_Check(py_item))
- {
- size_t m = PyLong_AsSize_t(py_item);
- if (m >= n)
- {
- PyErr_SetString(PyExc_TypeError, "Membership cannot exceed number of nodes.");
- return NULL;
- }
- else
- initial_membership[v] = m;
- }
- else
- {
- PyErr_SetString(PyExc_TypeError, "Expected integer value for membership vector.");
- return NULL;
- }
- }
+ vector<size_t> initial_membership = create_size_t_vector(py_initial_membership);
partition = new CPMVertexPartition(graph, initial_membership, resolution_parameter);
}
@@ -485,34 +384,7 @@ extern "C"
// If necessary create an initial partition
if (py_initial_membership != NULL && py_initial_membership != Py_None)
{
-
- vector<size_t> initial_membership;
-
- #ifdef DEBUG
- cerr << "Reading initial membership." << endl;
- #endif
- size_t n = PyList_Size(py_initial_membership);
- initial_membership.resize(n);
- for (size_t v = 0; v < n; v++)
- {
- PyObject* py_item = PyList_GetItem(py_initial_membership, v);
- if (PyNumber_Check(py_item) && PyIndex_Check(py_item))
- {
- size_t m = PyLong_AsSize_t(py_item);
- if (m >= n)
- {
- PyErr_SetString(PyExc_TypeError, "Membership cannot exceed number of nodes.");
- return NULL;
- }
- else
- initial_membership[v] = m;
- }
- else
- {
- PyErr_SetString(PyExc_TypeError, "Expected integer value for membership vector.");
- return NULL;
- }
- }
+ vector<size_t> initial_membership = create_size_t_vector(py_initial_membership);
partition = new RBERVertexPartition(graph, initial_membership, resolution_parameter);
}
@@ -561,34 +433,7 @@ extern "C"
// If necessary create an initial partition
if (py_initial_membership != NULL && py_initial_membership != Py_None)
{
-
- vector<size_t> initial_membership;
-
- #ifdef DEBUG
- cerr << "Reading initial membership." << endl;
- #endif
- size_t n = PyList_Size(py_initial_membership);
- initial_membership.resize(n);
- for (size_t v = 0; v < n; v++)
- {
- PyObject* py_item = PyList_GetItem(py_initial_membership, v);
- if (PyNumber_Check(py_item) && PyIndex_Check(py_item))
- {
- size_t m = PyLong_AsSize_t(py_item);
- if (m >= n)
- {
- PyErr_SetString(PyExc_TypeError, "Membership cannot exceed number of nodes.");
- return NULL;
- }
- else
- initial_membership[v] = m;
- }
- else
- {
- PyErr_SetString(PyExc_TypeError, "Expected integer value for membership vector.");
- return NULL;
- }
- }
+ vector<size_t> initial_membership = create_size_t_vector(py_initial_membership);
partition = new RBConfigurationVertexPartition(graph, initial_membership, resolution_parameter);
}
@@ -663,11 +508,7 @@ extern "C"
PyObject* node_sizes = PyList_New(n);
for (size_t v = 0; v < n; v++)
{
- #ifdef IS_PY3K
- PyObject* item = PyLong_FromSize_t(graph->node_size(v));
- #else
- PyObject* item = PyInt_FromSize_t(graph->node_size(v));
- #endif
+ PyObject* item = PyLong_FromSize_t(graph->node_size(v));
PyList_SetItem(node_sizes, v, item);
}
@@ -695,30 +536,19 @@ extern "C"
cerr << "from_coarse_partition();" << endl;
#endif
- size_t n = PyList_Size(py_membership);
vector<size_t> membership;
- membership.resize(n);
- for (size_t v = 0; v < n; v++)
+ try
{
- PyObject* py_item = PyList_GetItem(py_membership, v);
- if (PyNumber_Check(py_item) && PyIndex_Check(py_item))
- {
- size_t m = PyLong_AsSize_t(py_item);
- if (m >= n)
- {
- PyErr_SetString(PyExc_TypeError, "Membership cannot exceed number of nodes.");
- return NULL;
- }
- else
- membership[v] = m;
- }
- else
- {
- PyErr_SetString(PyExc_TypeError, "Expected integer value for membership vector.");
- return NULL;
- }
+ membership = create_size_t_vector(py_membership);
+ }
+ catch (std::exception& e )
+ {
+ string s = "Could not create membership vector: " + string(e.what());
+ PyErr_SetString(PyExc_BaseException, s.c_str());
+ return NULL;
}
+
#ifdef DEBUG
cerr << "Capsule partition at address " << py_partition << endl;
#endif
@@ -731,33 +561,18 @@ extern "C"
if (py_coarse_node != NULL && py_coarse_node != Py_None)
{
- cerr << "Get coarse node list" << endl;
- size_t n = PyList_Size(py_coarse_node);
vector<size_t> coarse_node;
- coarse_node.resize(n);
- for (size_t v = 0; v < n; v++)
+ try
{
- PyObject* py_item = PyList_GetItem(py_coarse_node, v);
-
- if (PyNumber_Check(py_item) && PyIndex_Check(py_item))
- {
- size_t m = PyLong_AsSize_t(py_item);
- if (m >= n)
- {
- PyErr_SetString(PyExc_TypeError, "Coarse node cannot exceed number of nodes.");
- return NULL;
- }
- else
- coarse_node[v] = m;
- }
- else
- {
- PyErr_SetString(PyExc_TypeError, "Expected integer value for coarse vector.");
- return NULL;
- }
+ coarse_node = create_size_t_vector(py_coarse_node);
+ }
+ catch (std::exception& e )
+ {
+ string s = "Could not create coarse node vector: " + string(e.what());
+ PyErr_SetString(PyExc_BaseException, s.c_str());
+ return NULL;
}
- cerr << "Got coarse node list" << endl;
partition->from_coarse_partition(membership, coarse_node);
}
else
@@ -1257,11 +1072,7 @@ extern "C"
PyObject* py_membership = PyList_New(n);
for (size_t v = 0; v < n; v++)
{
- #ifdef IS_PY3K
- PyObject* item = PyLong_FromSize_t(partition->membership(v));
- #else
- PyObject* item = PyInt_FromSize_t(partition->membership(v));
- #endif
+ PyObject* item = PyLong_FromSize_t(partition->membership(v));
PyList_SetItem(py_membership, v, item);
}
return py_membership;
@@ -1296,32 +1107,16 @@ extern "C"
cerr << "Using partition at address " << partition << endl;
#endif
- size_t n = PyList_Size(py_membership);
- vector<size_t> membership;
- membership.resize(n);
- for (size_t v = 0; v < n; v++)
+ try
{
- PyObject* py_item = PyList_GetItem(py_membership, v);
-
- if (PyNumber_Check(py_item) && PyIndex_Check(py_item))
- {
- size_t m = PyLong_AsSize_t(py_item);
- if (m >= n)
- {
- PyErr_SetString(PyExc_TypeError, "Membership cannot exceed number of nodes.");
- return NULL;
- }
- else
- membership[v] = m;
- }
- else
- {
- PyErr_SetString(PyExc_TypeError, "Expected integer value for membership vector.");
- return NULL;
- }
+ partition->set_membership(create_size_t_vector(py_membership));
+ }
+ catch (std::exception& e )
+ {
+ string s = "Could not set membership: " + string(e.what());
+ PyErr_SetString(PyExc_BaseException, s.c_str());
+ return NULL;
}
-
- partition->set_membership(membership);
#ifdef DEBUG
cerr << "Exiting set_membership();" << endl;
=====================================
tests/test_Optimiser.py
=====================================
@@ -2,33 +2,29 @@ import unittest
import igraph as ig
import leidenalg
-import sys
-PY3 = (sys.version > '3');
-
-if PY3:
- from functools import reduce
+from functools import reduce
class OptimiserTest(unittest.TestCase):
def setUp(self):
- self.optimiser = leidenalg.Optimiser();
+ self.optimiser = leidenalg.Optimiser()
def test_move_nodes(self):
- G = ig.Graph.Full(100);
- partition = leidenalg.CPMVertexPartition(G, resolution_parameter=0.5);
- self.optimiser.move_nodes(partition, consider_comms=leidenalg.ALL_NEIGH_COMMS);
+ G = ig.Graph.Full(100)
+ partition = leidenalg.CPMVertexPartition(G, resolution_parameter=0.5)
+ self.optimiser.move_nodes(partition, consider_comms=leidenalg.ALL_NEIGH_COMMS)
self.assertListEqual(
partition.sizes(), [100],
- msg="CPMVertexPartition(resolution_parameter=0.5) of complete graph after move nodes incorrect.");
+ msg="CPMVertexPartition(resolution_parameter=0.5) of complete graph after move nodes incorrect.")
def test_move_nodes_with_max_comm_size(self):
- G = ig.Graph.Full(100);
- partition = leidenalg.CPMVertexPartition(G, resolution_parameter=0.5);
+ G = ig.Graph.Full(100)
+ partition = leidenalg.CPMVertexPartition(G, resolution_parameter=0.5)
self.optimiser.max_comm_size = 17
- self.optimiser.move_nodes(partition, consider_comms=leidenalg.ALL_NEIGH_COMMS);
+ self.optimiser.move_nodes(partition, consider_comms=leidenalg.ALL_NEIGH_COMMS)
self.assertListEqual(
partition.sizes(), [17, 17, 17, 17, 17, 15],
- msg="CPMVertexPartition(resolution_parameter=0.5) of complete graph after move nodes (max_comm_size=17) incorrect.");
+ msg="CPMVertexPartition(resolution_parameter=0.5) of complete graph after move nodes (max_comm_size=17) incorrect.")
def test_move_nodes_with_fixed(self):
# One edge plus singleton, but the two connected nodes are fixed
@@ -36,76 +32,76 @@ class OptimiserTest(unittest.TestCase):
is_membership_fixed = [True, False, True]
partition = leidenalg.CPMVertexPartition(
G,
- resolution_parameter=0.1);
- self.optimiser.move_nodes(partition, is_membership_fixed=is_membership_fixed, consider_comms=leidenalg.ALL_NEIGH_COMMS);
+ resolution_parameter=0.1)
+ self.optimiser.move_nodes(partition, is_membership_fixed=is_membership_fixed, consider_comms=leidenalg.ALL_NEIGH_COMMS)
self.assertListEqual(
partition.sizes(), [1, 1, 1],
- msg="CPMVertexPartition(resolution_parameter=0.1) of one edge plus singleton after move nodes with fixed nodes is incorrect.");
+ msg="CPMVertexPartition(resolution_parameter=0.1) of one edge plus singleton after move nodes with fixed nodes is incorrect.")
def test_merge_nodes(self):
- G = ig.Graph.Full(100);
- partition = leidenalg.CPMVertexPartition(G, resolution_parameter=0.5);
- self.optimiser.merge_nodes(partition, consider_comms=leidenalg.ALL_NEIGH_COMMS);
+ G = ig.Graph.Full(100)
+ partition = leidenalg.CPMVertexPartition(G, resolution_parameter=0.5)
+ self.optimiser.merge_nodes(partition, consider_comms=leidenalg.ALL_NEIGH_COMMS)
self.assertListEqual(
partition.sizes(), [100],
- msg="CPMVertexPartition(resolution_parameter=0.5) of complete graph after merge nodes incorrect.");
+ msg="CPMVertexPartition(resolution_parameter=0.5) of complete graph after merge nodes incorrect.")
self.assertEqual(
partition.total_weight_in_all_comms(),
G.ecount(),
- msg="total_weight_in_all_comms not equal to ecount of graph.");
+ msg="total_weight_in_all_comms not equal to ecount of graph.")
def test_merge_nodes_with_max_comm_size(self):
- G = ig.Graph.Full(100);
- partition = leidenalg.CPMVertexPartition(G, resolution_parameter=0.5);
+ G = ig.Graph.Full(100)
+ partition = leidenalg.CPMVertexPartition(G, resolution_parameter=0.5)
self.optimiser.max_comm_size = 17
- self.optimiser.merge_nodes(partition, consider_comms=leidenalg.ALL_NEIGH_COMMS);
+ self.optimiser.merge_nodes(partition, consider_comms=leidenalg.ALL_NEIGH_COMMS)
self.assertListEqual(
partition.sizes(), [17, 17, 17, 17, 17, 15],
- msg="CPMVertexPartition(resolution_parameter=0.5) of complete graph after merge nodes (max_comm_size=17) incorrect.");
+ msg="CPMVertexPartition(resolution_parameter=0.5) of complete graph after merge nodes (max_comm_size=17) incorrect.")
def test_diff_move_node_optimality(self):
- G = ig.Graph.Erdos_Renyi(100, p=5./100, directed=False, loops=False);
- partition = leidenalg.CPMVertexPartition(G, resolution_parameter=0.1);
+ G = ig.Graph.Erdos_Renyi(100, p=5./100, directed=False, loops=False)
+ partition = leidenalg.CPMVertexPartition(G, resolution_parameter=0.1)
while 0 < self.optimiser.move_nodes(partition, consider_comms=leidenalg.ALL_NEIGH_COMMS):
- pass;
+ pass
for v in G.vs:
- neigh_comms = set(partition.membership[u.index] for u in v.neighbors());
+ neigh_comms = set(partition.membership[u.index] for u in v.neighbors())
for c in neigh_comms:
self.assertLessEqual(
partition.diff_move(v.index, c), 1e-10, # Allow for a small difference up to rounding error.
- msg="Was able to move a node to a better community, violating node optimality.");
+ msg="Was able to move a node to a better community, violating node optimality.")
def test_optimiser(self):
- G = reduce(ig.Graph.disjoint_union, (ig.Graph.Tree(10, 3, mode=ig.TREE_UNDIRECTED) for i in range(10)));
- partition = leidenalg.CPMVertexPartition(G, resolution_parameter=0);
- self.optimiser.consider_comms=leidenalg.ALL_NEIGH_COMMS;
- self.optimiser.optimise_partition(partition);
+ G = reduce(ig.Graph.disjoint_union, (ig.Graph.Tree(10, 3, mode=ig.TREE_UNDIRECTED) for i in range(10)))
+ partition = leidenalg.CPMVertexPartition(G, resolution_parameter=0)
+ self.optimiser.consider_comms=leidenalg.ALL_NEIGH_COMMS
+ self.optimiser.optimise_partition(partition)
self.assertListEqual(
partition.sizes(), 10*[10],
- msg="After optimising partition failed to find different components with CPMVertexPartition(resolution_parameter=0)");
+ msg="After optimising partition failed to find different components with CPMVertexPartition(resolution_parameter=0)")
def test_optimiser_with_max_comm_size(self):
- G = ig.Graph.Full(100);
- partition = leidenalg.CPMVertexPartition(G, resolution_parameter=0);
- self.optimiser.consider_comms=leidenalg.ALL_NEIGH_COMMS;
+ G = ig.Graph.Full(100)
+ partition = leidenalg.CPMVertexPartition(G, resolution_parameter=0)
+ self.optimiser.consider_comms=leidenalg.ALL_NEIGH_COMMS
self.optimiser.max_comm_size = 10
- self.optimiser.optimise_partition(partition);
+ self.optimiser.optimise_partition(partition)
self.assertListEqual(
partition.sizes(), 10*[10],
- msg="After optimising partition (max_comm_size=10) failed to find different components with CPMVertexPartition(resolution_parameter=0)");
+ msg="After optimising partition (max_comm_size=10) failed to find different components with CPMVertexPartition(resolution_parameter=0)")
def test_optimiser_split_with_max_comm_size(self):
- G = ig.Graph.Full(100);
- partition = leidenalg.CPMVertexPartition(G, resolution_parameter=0.5);
- self.optimiser.merge_nodes(partition, consider_comms=leidenalg.ALL_NEIGH_COMMS);
+ G = ig.Graph.Full(100)
+ partition = leidenalg.CPMVertexPartition(G, resolution_parameter=0.5)
+ self.optimiser.merge_nodes(partition, consider_comms=leidenalg.ALL_NEIGH_COMMS)
self.assertListEqual(
partition.sizes(), [100],
- msg="CPMVertexPartition(resolution_parameter=0.5) of complete graph after merge nodes incorrect.");
+ msg="CPMVertexPartition(resolution_parameter=0.5) of complete graph after merge nodes incorrect.")
self.optimiser.max_comm_size = 10
- self.optimiser.optimise_partition(partition);
+ self.optimiser.optimise_partition(partition)
self.assertListEqual(
partition.sizes(), 10*[10],
- msg="After optimising partition (max_comm_size=10) failed to find different components with CPMVertexPartition(resolution_parameter=0.5)");
+ msg="After optimising partition (max_comm_size=10) failed to find different components with CPMVertexPartition(resolution_parameter=0.5)")
def test_optimiser_with_is_membership_fixed(self):
G = ig.Graph.Full(3)
@@ -148,28 +144,28 @@ class OptimiserTest(unittest.TestCase):
def test_neg_weight_bipartite(self):
- G = ig.Graph.Full_Bipartite(50, 50);
- G.es['weight'] = -0.1;
- partition = leidenalg.CPMVertexPartition(G, resolution_parameter=-0.1, weights='weight');
- self.optimiser.consider_comms=leidenalg.ALL_COMMS;
- self.optimiser.optimise_partition(partition);
+ G = ig.Graph.Full_Bipartite(50, 50)
+ G.es['weight'] = -0.1
+ partition = leidenalg.CPMVertexPartition(G, resolution_parameter=-0.1, weights='weight')
+ self.optimiser.consider_comms=leidenalg.ALL_COMMS
+ self.optimiser.optimise_partition(partition)
self.assertListEqual(
partition.sizes(), 2*[50],
- msg="After optimising partition failed to find bipartite structure with CPMVertexPartition(resolution_parameter=-0.1)");
+ msg="After optimising partition failed to find bipartite structure with CPMVertexPartition(resolution_parameter=-0.1)")
def test_resolution_profile(self):
- G = ig.Graph.Famous('Zachary');
- profile = self.optimiser.resolution_profile(G, leidenalg.CPMVertexPartition, resolution_range=(0,1));
+ G = ig.Graph.Famous('Zachary')
+ profile = self.optimiser.resolution_profile(G, leidenalg.CPMVertexPartition, resolution_range=(0,1))
self.assertListEqual(
profile[0].sizes(), [G.vcount()],
- msg="Resolution profile incorrect: at resolution 0, not equal to a single community for CPM.");
+ msg="Resolution profile incorrect: at resolution 0, not equal to a single community for CPM.")
self.assertListEqual(
profile[-1].sizes(), [1]*G.vcount(),
- msg="Resolution profile incorrect: at resolution 1, not equal to a singleton partition for CPM.");
+ msg="Resolution profile incorrect: at resolution 1, not equal to a singleton partition for CPM.")
#%%
if __name__ == '__main__':
#%%
- unittest.main(verbosity=3);
- suite = unittest.TestLoader().discover('.');
- unittest.TextTestRunner(verbosity=1).run(suite);
+ unittest.main(verbosity=3)
+ suite = unittest.TestLoader().discover('.')
+ unittest.TextTestRunner(verbosity=1).run(suite)
=====================================
tests/test_VertexPartition.py
=====================================
@@ -6,13 +6,11 @@ from copy import deepcopy
from ddt import ddt, data, unpack
-import sys
-PY3 = (sys.version > '3');
#%%
def name_object(obj, name):
- obj.__name__ = name;
- return obj;
+ obj.__name__ = name
+ return obj
graphs = [
###########################################################################
@@ -58,7 +56,7 @@ graphs = [
'Lattice_undirected'),
name_object(ig.Graph.Lattice([100], nei=3, directed=True, mutual=False, circular=True),
'Lattice_directed')
- ];
+ ]
bipartite_graph = name_object(
ig.Graph.Bipartite([0, 0, 0, 0, 1, 1, 1, 1],
@@ -75,91 +73,88 @@ bipartite_graph = name_object(
'bipartite_example')
def make_weighted(G):
- m = G.ecount();
- if PY3:
- G.es['weight'] = [random.random() for i in range(G.ecount())];
- else:
- G.es['weight'] = [random.random() for i in xrange(G.ecount())];
- G.__name__ += '_weighted';
- return G;
+ m = G.ecount()
+ G.es['weight'] = [random.random() for i in range(G.ecount())]
+ G.__name__ += '_weighted'
+ return G
-graphs += [make_weighted(H) for H in graphs];
+graphs += [make_weighted(H) for H in graphs]
class BaseTest:
@ddt
class MutableVertexPartitionTest(unittest.TestCase):
def setUp(self):
- self.optimiser = leidenalg.Optimiser();
+ self.optimiser = leidenalg.Optimiser()
@data(*graphs)
def test_move_nodes(self, graph):
if 'weight' in graph.es.attributes() and self.partition_type == leidenalg.SignificanceVertexPartition:
- raise unittest.SkipTest('Significance doesn\'t handle weighted graphs');
+ raise unittest.SkipTest('Significance doesn\'t handle weighted graphs')
if 'weight' in graph.es.attributes():
- partition = self.partition_type(graph, weights='weight');
+ partition = self.partition_type(graph, weights='weight')
else:
- partition = self.partition_type(graph);
+ partition = self.partition_type(graph)
for v in range(graph.vcount()):
if graph.degree(v) >= 1:
- u = graph.neighbors(v)[0];
- diff = partition.diff_move(v, partition.membership[u]);
- q1 = partition.quality();
- partition.move_node(v, partition.membership[u]);
- q2 = partition.quality();
+ u = graph.neighbors(v)[0]
+ diff = partition.diff_move(v, partition.membership[u])
+ q1 = partition.quality()
+ partition.move_node(v, partition.membership[u])
+ q2 = partition.quality()
self.assertAlmostEqual(
q2 - q1,
diff,
places=5,
msg="Difference in quality ({0}) not equal to calculated difference ({1})".format(
- q2 - q1, diff));
+ q2 - q1, diff))
@data(*graphs)
def test_aggregate_partition(self, graph):
if 'weight' in graph.es.attributes() and self.partition_type != leidenalg.SignificanceVertexPartition:
- partition = self.partition_type(graph, weights='weight');
+ partition = self.partition_type(graph, weights='weight')
else:
- partition = self.partition_type(graph);
- self.optimiser.move_nodes(partition);
- aggregate_partition = partition.aggregate_partition();
+ partition = self.partition_type(graph)
+ self.optimiser.move_nodes(partition)
+ aggregate_partition = partition.aggregate_partition()
self.assertAlmostEqual(
partition.quality(),
aggregate_partition.quality(),
places=5,
- msg='Quality not equal for aggregate partition.');
- self.optimiser.move_nodes(aggregate_partition);
- partition.from_coarse_partition(aggregate_partition);
+ msg='Quality not equal for aggregate partition.')
+ self.optimiser.move_nodes(aggregate_partition)
+ partition.from_coarse_partition(aggregate_partition)
self.assertAlmostEqual(
partition.quality(),
aggregate_partition.quality(),
places=5,
- msg='Quality not equal from coarser partition.');
+ msg='Quality not equal from coarser partition.')
@data(*graphs)
def test_total_weight_in_all_comms(self, graph):
if 'weight' in graph.es.attributes() and self.partition_type != leidenalg.SignificanceVertexPartition:
- partition = self.partition_type(graph, weights='weight');
+ partition = self.partition_type(graph, weights='weight')
else:
- partition = self.partition_type(graph);
- self.optimiser.optimise_partition(partition);
- s = sum([partition.total_weight_in_comm(c) for c,_ in enumerate(partition)]);
+ partition = self.partition_type(graph)
+ self.optimiser.optimise_partition(partition)
+ s = sum([partition.total_weight_in_comm(c) for c,_ in enumerate(partition)])
self.assertAlmostEqual(
s,
partition.total_weight_in_all_comms(),
places=5,
msg='Total weight in all communities ({0}) not equal to the sum of the weight in all communities ({1}).'.format(
s, partition.total_weight_in_all_comms())
- );
+ )
@data(*graphs)
def test_copy(self, graph):
if 'weight' in graph.es.attributes() and self.partition_type != leidenalg.SignificanceVertexPartition:
- partition = self.partition_type(graph, weights='weight');
+ partition = self.partition_type(graph, weights='weight')
else:
- partition = self.partition_type(graph);
+ partition = self.partition_type(graph)
- self.optimiser.optimise_partition(partition);
+ self.optimiser.optimise_partition(partition)
partition2 = deepcopy(partition)
@@ -186,23 +181,23 @@ class BaseTest:
class ModularityVertexPartitionTest(BaseTest.MutableVertexPartitionTest):
def setUp(self):
- super(ModularityVertexPartitionTest, self).setUp();
- self.partition_type = leidenalg.ModularityVertexPartition;
+ super(ModularityVertexPartitionTest, self).setUp()
+ self.partition_type = leidenalg.ModularityVertexPartition
class RBERVertexPartitionTest(BaseTest.MutableVertexPartitionTest):
def setUp(self):
- super(RBERVertexPartitionTest, self).setUp();
- self.partition_type = leidenalg.RBERVertexPartition;
+ super(RBERVertexPartitionTest, self).setUp()
+ self.partition_type = leidenalg.RBERVertexPartition
class RBConfigurationVertexPartitionTest(BaseTest.MutableVertexPartitionTest):
def setUp(self):
- super(RBConfigurationVertexPartitionTest, self).setUp();
- self.partition_type = leidenalg.RBConfigurationVertexPartition;
+ super(RBConfigurationVertexPartitionTest, self).setUp()
+ self.partition_type = leidenalg.RBConfigurationVertexPartition
class CPMVertexPartitionTest(BaseTest.MutableVertexPartitionTest):
def setUp(self):
- super(CPMVertexPartitionTest, self).setUp();
- self.partition_type = leidenalg.CPMVertexPartition;
+ super(CPMVertexPartitionTest, self).setUp()
+ self.partition_type = leidenalg.CPMVertexPartition
def test_Bipartite(self):
graph = bipartite_graph
@@ -215,17 +210,17 @@ class CPMVertexPartitionTest(BaseTest.MutableVertexPartitionTest):
class SurpriseVertexPartitionTest(BaseTest.MutableVertexPartitionTest):
def setUp(self):
- super(SurpriseVertexPartitionTest, self).setUp();
- self.partition_type = leidenalg.SurpriseVertexPartition;
+ super(SurpriseVertexPartitionTest, self).setUp()
+ self.partition_type = leidenalg.SurpriseVertexPartition
class SignificanceVertexPartitionTest(BaseTest.MutableVertexPartitionTest):
def setUp(self):
- super(SignificanceVertexPartitionTest, self).setUp();
- self.partition_type = leidenalg.SignificanceVertexPartition;
+ super(SignificanceVertexPartitionTest, self).setUp()
+ self.partition_type = leidenalg.SignificanceVertexPartition
#%%
if __name__ == '__main__':
#%%
- unittest.main(verbosity=3);
- suite = unittest.TestLoader().discover('.');
- unittest.TextTestRunner(verbosity=1).run(suite);
+ unittest.main(verbosity=3)
+ suite = unittest.TestLoader().discover('.')
+ unittest.TextTestRunner(verbosity=1).run(suite)
View it on GitLab: https://salsa.debian.org/med-team/python-leidenalg/-/compare/d8851a3c61c3ab166e7137e7aa1bec8aba8bb2ac...6961a5fd4911492de35b798dfb9459cb870ce91d
--
View it on GitLab: https://salsa.debian.org/med-team/python-leidenalg/-/compare/d8851a3c61c3ab166e7137e7aa1bec8aba8bb2ac...6961a5fd4911492de35b798dfb9459cb870ce91d
You're receiving this email because of your account on salsa.debian.org.
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://alioth-lists.debian.net/pipermail/debian-med-commit/attachments/20210703/64d16d19/attachment-0001.htm>
More information about the debian-med-commit
mailing list