Detectors¶
Every detector takes a graph and returns a partition as dict[node, community]. Isolated nodes are assigned community -1.
Two of these are this library's own algorithms — rimpso and hpmocd. The other eight entry points re-implement published methods by other authors; see Algorithms for the paper, the selection rule and the original implementation (where the authors released one) behind each.
This library's algorithms¶
pymocd.rimpso
¶
rimpso(
graph: Any,
pop_size: int = 100,
num_gens: int = 100,
inertia: float = 0.4,
cognitive: float = 0.7,
social: float = 0.7,
local_rate: float = 0.35,
archive: int = 100,
ls_period: int = 10,
seed: int = 0,
) -> typing.Any
rimpso — multi-objective particle swarm optimisation over the Constant
Potts Model. Returns the selected partition as dict[node, community];
isolated nodes get -1.
CPM, H(gamma) = sum_c [e_c - gamma * C(n_c,2)], is split the way HP-MOCD
splits modularity, into a cut fraction and a pair coverage. Every resolution
gamma is a weighted sum of that same pair, so the Pareto front the swarm
builds is the graph's whole resolution profile and gamma stops being a
parameter the caller has to guess.
Selection is label-free and has no parameter: of the archive's members, the one a degree-corrected assortative block model fits best once its own free densities are paid for. Both degenerate partitions carry no evidence and pay the penalty anyway, so there is no degeneracy filter and no fallback stage.
Deterministic: the same graph and the same parameters, seed included, give
the same partition on any number of threads.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
pop_size
|
int
|
particles in the swarm, one per rung of the resolution ladder. |
100
|
num_gens
|
int
|
generations to fly; the search always runs all of them. |
100
|
inertia
|
float
|
fraction of a node's instability carried to the next iteration. |
0.4
|
cognitive
|
float
|
pull toward the particle's own best partition. |
0.7
|
social
|
float
|
pull toward a leader drawn from the archive by binary tournament on crowding distance. |
0.7
|
local_rate
|
float
|
per-node rate of the resolution-directed CPM local move, applied on the iterations the full local search does not run. |
0.35
|
archive
|
int
|
capacity of the external Pareto archive. |
100
|
ls_period
|
int
|
run the full local search — drive the particle back to a local
optimum of CPM at its own resolution, then sweep for community merges —
every |
10
|
seed
|
int
|
run seed. The default, 0, contributes nothing to the random stream, so it reproduces the single trajectory this searched before the seed was a parameter; any other value flies an independent one. |
0
|
seed is the random seed, not a seeding budget: there is no seeding local
search and no seed_rounds. Every particle starts at a raw scatter and the
flight does all of the optimisation. Driving each particle to a CPM local optimum
first was measured to be worth only a handful of iterations, and asymptotically to
cost quality, because a particle already at a local optimum must be dragged out of
it before it can move.
pymocd.hpmocd
¶
hpmocd(graph: Any) -> builtins.dict[builtins.int, builtins.int]
Run HP-MOCD (NSGA-II) with its published defaults.
Returns dict[node, community]. Isolated nodes get -1.
Tunable HP-MOCD
hpmocd takes the graph and nothing else: it runs at the published configuration (pop_size=100, num_gens=100, cross_rate=0.7, mut_rate=0.5). The pymocd.HpMocd class exposes the same search with those four as constructor arguments, plus set_objectives for plugging in your own Python objective functions and set_on_generation for a per-generation callback.
Re-implemented baselines¶
pymocd.cdrme
¶
cdrme(
graph: Any,
alpha_walk: float = 1.0,
n_walk: int = 50,
pop_size: int = 300,
elite_size: int = 300,
alpha_mut: float = 0.5,
mut_sweeps: int = 10,
) -> builtins.dict[builtins.int, builtins.int]
Run CDRME (Dabaghi-Zarandi, Afkhami & Ashoori, "Community Detection method based on Random walk and Multi objective Evolutionary algorithm in complex networks", Journal of Network and Computer Applications 234:104070, 2025) — softmax-weighted random walks seeded at degree-weighted centres compose a primary community set, a population of stochastic agglomerative merge chains diversifies it under the paper's linkage objective (Eq. 12), and a similarity-driven mutation repairs the weakly attached nodes.
Eq. (12) adds innerLinkage (Eq. 9) and outerLinkage (Eq. 10) into one
maximised scalar, so there is no Pareto front and no cdrme_fronts. The
paper's own selector (Sec. 4.4.4) names three "evaluation measures"; NMI
needs ground truth and Density is maximised by the single community, so the
shipped rule is max-modularity, which is what the authors' own code selects
on.
Written from the paper. The authors' reference implementation is a private notebook, not a published repository.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
graph
|
Any
|
networkx.Graph or igraph.Graph (integer node ids). |
required |
alpha_walk
|
float
|
Eq. (7) walk-length coefficient, the paper's 1 to 2. Since
|
1.0
|
n_walk
|
int
|
walks per centre (Algorithm 1); the paper gives no value. |
50
|
pop_size
|
int
|
|
300
|
elite_size
|
int
|
|
300
|
alpha_mut
|
float
|
Sec. 4.4.2 mutation threshold on the |
0.5
|
mut_sweeps
|
int
|
cap on the 4.4.2 <-> 4.4.3 loop, which the paper leaves unbounded. The loop also stops on the first sweep that moves no gene. |
10
|
Returns:
| Type | Description |
|---|---|
dict[int, int]
|
|
pymocd.mmcomo
¶
mmcomo(
graph: Any,
pop_size: int = 100,
num_gens: int = 50,
cross_rate: float = 0.1,
mut_rate: float = 0.1,
gap: int = 10,
beta: float = 0.05,
) -> typing.Any
MMCoMO macro-micro co-evolutionary detector (Zhang et al.); returns the max-modularity member of the merged rank-1 front. Isolated nodes get -1.
pymocd.ccm
¶
ccm(
graph: Any,
pop_size: int = 200,
num_gens: int = 100,
cross_rate: float = 0.8,
mut_rate: float = 0.014705882352941176,
r: float = 1.0,
alpha: float = 1.0,
divisions: int = 12,
) -> builtins.dict[builtins.int, builtins.int]
Run NSGA-III-CCM (Shaik, Ravi & Deb, SN Computer Science 2:13, 2021) — NSGA-III over the three maximized objectives (Community Score, Community Fitness, Modularity). Returns the max-modularity member of the rank-1 Pareto front (the paper's recommended ground-truth-free decision rule).
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
graph
|
Any
|
networkx.Graph or igraph.Graph (integer node ids). |
required |
r
|
float
|
Community Score power-mean exponent (Shaik default 1). |
1.0
|
alpha
|
float
|
Community Fitness exponent (Shaik default 1). |
1.0
|
divisions
|
int
|
Das–Dennis reference-point granularity |
12
|
Returns:
| Type | Description |
|---|---|
dict[int, int]
|
|
pymocd.krm
¶
krm(
graph: Any,
pop_size: int = 100,
num_gens: int = 100,
cross_rate: float = 0.8,
mut_rate: float = 0.029411764705882353,
divisions: int = 12,
) -> builtins.dict[builtins.int, builtins.int]
Run NSGA-III-KRM (Shaik, Ravi & Deb, SN Computer Science 2:13, 2021) — NSGA-III over (Kernel-K-Means, Ratio-Cut, Modularity); KKM & Ratio-Cut minimized, Modularity maximized. Returns the max-modularity member of the rank-1 Pareto front (the paper's recommended ground-truth-free decision rule).
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
graph
|
Any
|
networkx.Graph or igraph.Graph (integer node ids). |
required |
divisions
|
int
|
Das–Dennis reference-point granularity |
12
|
Returns:
| Type | Description |
|---|---|
dict[int, int]
|
|
pymocd.gdpso
¶
gdpso(
graph: Any,
pop_size: int = 100,
num_gens: int = 250,
w: float = 0.7298,
c1: float = 1.4961,
c2: float = 1.4961,
mut_rate: float = 0.1,
mut_frac: float = 0.1,
lpa_sweeps: int = 5,
) -> builtins.dict[builtins.int, builtins.int]
Run GDPSO (Cai, Gong, Ma, Ruan, Yuan, Jiao, "Greedy discrete particle swarm
optimization for large-scale social network clustering", Information
Sciences 316:503–516, 2015) — a swarm of label vectors, each seeded by a
short asynchronous label-propagation run, that once per generation turns a
sigmoid of the velocity into a binary per-node move mask and offers every
masked node an exact single-node modularity move. Returns the best position
the swarm ever held; GDPSO is single-objective (Newman–Girvan modularity),
so there is no Pareto front and no gdpso_fronts.
Written from a specification of the authors' public reference implementation; no reference source was copied.
Note pbest and gbest carry no label information — they enter only as
two indicator bits shifting a node's move probability — so in practice this
behaves as the best of pop_size LPA seeds, each polished by Louvain
local-moving. lpa_sweeps, not num_gens, is the lever on seed
diversity. GDPSO also inherits modularity's resolution limit whole.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
graph
|
Any
|
networkx.Graph or igraph.Graph (integer node ids). |
required |
w
|
float
|
inertia weight on the previous velocity (Clerc constant, inherited from real-valued PSO; the velocity is re-binarized every generation). |
0.7298
|
c1
|
float
|
cognitive weight, applied to the |
1.4961
|
c2
|
float
|
social weight, applied to the |
1.4961
|
mut_rate
|
float
|
per-node label-broadcast probability inside a mutated particle. |
0.1
|
mut_frac
|
float
|
fraction of the swarm that is mutated each generation. The
reference overloads a single 0.1 for this and for |
0.1
|
lpa_sweeps
|
int
|
asynchronous label-propagation sweeps seeding each particle. |
5
|
Returns:
| Type | Description |
|---|---|
dict[int, int]
|
|
pymocd.mocd_q
¶
mocd_q(
graph: Any,
pop_size: int = 100,
num_gens: int = 100,
cross_rate: float = 0.9,
mut_rate: float = 0.1,
) -> builtins.dict[builtins.int, builtins.int]
Run Shi-MOCD (Shi, Yan, Cai, Wu 2012) — PESA-II over Shi's decomposed-modularity objectives (intra/inter). Returns the max-modularity member of the Pareto front (MOCD-Q selection, Shi Eq. 3.8).
Defaults (pop=100, gen=100, C_R=0.9, M_R=0.1) are the repo's HP-MOCD-parity benchmark budget, NOT Shi's published configuration — that is pc=0.6, pm=0.4 with per-graph ip/ep/gen from Table 1; pass those via kwargs.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
graph
|
Any
|
networkx.Graph or igraph.Graph (integer node ids). |
required |
Returns:
| Type | Description |
|---|---|
dict[int, int]
|
|
pymocd.mocd_d
¶
mocd_d(
graph: Any,
pop_size: int = 100,
num_gens: int = 100,
cross_rate: float = 0.9,
mut_rate: float = 0.1,
rand_networks: int = 3,
) -> builtins.dict[builtins.int, builtins.int]
Shi-MOCD with the Max-Min Distance (MOCD-D) model selector (Shi et al.
2012, Eqs. 3.9–3.11): returns the Pareto-front member whose (intra, inter)
deviates most from rand_networks same-scale Erdős–Rényi control fronts.
Defaults (pop=100, gen=100, C_R=0.9, M_R=0.1) are the repo's HP-MOCD-parity benchmark budget, NOT Shi's published configuration — that is pc=0.6, pm=0.4 with per-graph ip/ep/gen from Table 1; pass those via kwargs.
Returns:
| Type | Description |
|---|---|
dict[int, int]
|
|
pymocd.moga_net
¶
moga_net(
graph: Any,
pop_size: int = 300,
num_gens: int = 30,
cross_rate: float = 0.8,
mut_rate: float = 0.2,
r: float = 2.0,
alpha: float = 1.0,
) -> builtins.dict[builtins.int, builtins.int]
Run MOGA-Net (Pizzuti, IEEE TEC 16(3):418–430, 2012) — NSGA-II over the (Community Score, Community Fitness) bi-objective. Returns the max-modularity member of the rank-1 Pareto front (Pizzuti Sec. V-E).
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
graph
|
Any
|
networkx.Graph or igraph.Graph (integer node ids). |
required |
r
|
float
|
Community Score power-mean exponent (resolution knob; higher helps at high mixing). TEVC 2012 Sec. VI-C fixes it at 2, which is the default here. |
2.0
|
alpha
|
float
|
Community Fitness exponent. It does not set a community size: in the per-node form used here CF ≤ Σ_i deg(i)^(1−alpha) for every alpha, with equality only for the single-community partition. It reweights who counts — alpha > 1 discounts high-degree nodes, so low-degree nodes' internal edges matter relatively more. Pizzuti default 1. |
1.0
|
Returns:
| Type | Description |
|---|---|
dict[int, int]
|
|
Deprecated aliases¶
pymocd.mr_mocd, pymocd.mr_mocd_fronts and pymocd.mr_mocd_select are the names this detector carried before it was renamed to RIMPSO; pymocd.scale and pymocd.scale_fronts are older still. All five are the same function objects as rimpso, rimpso_fronts and rimpso_select, kept so pinned callers keep working. They emit no warning and do not appear in the type stubs. Use the new names.