-
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathhet_calcs.py
128 lines (104 loc) · 4.58 KB
/
het_calcs.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
""" Some functions for calculating metrics of population heterogeneity. """
# Copyright (c) 2024-2025, Alex Plakantonakis.
#
# 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 <http://www.gnu.org/licenses/>.
import os
from collections import Counter
from numpy import log, ndarray
from .process import Process, ReversibleProcess, MichaelisMentenProcess, \
RegulatedProcess, RegulatedMichaelisMentenProcess
from .logging_config import logger
logger = logger.getChild(os.path.basename(__file__))
ProcessClasses = Process | ReversibleProcess | MichaelisMentenProcess | RegulatedProcess | RegulatedMichaelisMentenProcess
def get_het_processes(processes: list[ProcessClasses, ...]) -> list[ProcessClasses, ...]:
"""
Filter the heterogeneous processes from a given list of processes.
A process is heterogeneous if any of its parameters are defined as such.
"""
het_procs = list()
for proc in processes:
if isinstance(proc, MichaelisMentenProcess):
if proc.is_heterogeneous or proc.is_heterogeneous_Km:
het_procs.append(proc)
elif isinstance(proc, RegulatedMichaelisMentenProcess):
if proc.is_heterogeneous or proc.is_heterogeneous_Km:
het_procs.append(proc)
else:
if isinstance(proc.regulating_species, list): # multiple regulators
if sum(proc.is_heterogeneous_K50) > 0:
het_procs.append(proc)
elif isinstance(proc.regulating_species, str): # only one regulator
if proc.is_heterogeneous_K50:
het_procs.append(proc)
elif isinstance(proc, RegulatedProcess):
if proc.is_heterogeneous:
het_procs.append(proc)
else:
if isinstance(proc.regulating_species, list): # multiple regulators
if sum(proc.is_heterogeneous_K50) > 0:
het_procs.append(proc)
elif isinstance(proc.regulating_species, str): # only one regulator
if proc.is_heterogeneous_K50:
het_procs.append(proc)
elif isinstance(proc, ReversibleProcess):
if proc.is_heterogeneous or proc.is_heterogeneous_rev:
het_procs.append(proc)
else: # isinstance(proc, Process)
if proc.is_heterogeneous:
het_procs.append(proc)
return het_procs
def richness(arr: list | ndarray) -> int:
"""
Calculate the species richness, or how many subspecies
a species population comprises.
"""
return len(Counter(arr))
def idx_het(arr: list | ndarray) -> float:
"""
Calculate the Index of Heterogeneity ($\\psi$), defined as the probability
that two randomly chosen agents (without replacement) from a species
population belong to different subspecies.
- A homogeneous population returns 0.
- A heterogeneous population with two distinct subspecies of equal
fractional abundance (χ=0.5) *approaches* 0.5 as the population
size increases.
- A fully heterogeneous population returns 1.
"""
ck = Counter(arr) # counter of k values
n_tot = len(arr) # total number of entries in sequence `arr`
s = 0
for v in ck.values():
s += v * (v - 1)
try:
psi = 1 - s / (n_tot * (n_tot - 1))
except ZeroDivisionError:
psi = 0
return psi
def info_het(arr: list | ndarray) -> float:
"""
Information-theoretic measure of population heterogeneity.
- A homogeneous population returns 0.
- A heterogeneous population with two distinct subspecies of equal
fractional abundance (χ=0.5) returns ln(2). Note that this is
true regardless of the population size.
- For a fully heterogeneous population, the measure increases
with population size and has no upper limit.
"""
ck = Counter(arr) # counter of k values
n_tot = len(arr) # total number of agents
s = 0
for k, v in ck.items():
chi = v / n_tot
s -= chi * log(chi)
return s