abstochkin.het_calcs
Some functions for calculating metrics of population heterogeneity.
1""" Some functions for calculating metrics of population heterogeneity. """ 2 3# Copyright (c) 2024-2025, Alex Plakantonakis. 4# 5# This program is free software: you can redistribute it and/or modify 6# it under the terms of the GNU General Public License as published by 7# the Free Software Foundation, either version 3 of the License, or 8# (at your option) any later version. 9# 10# This program is distributed in the hope that it will be useful, 11# but WITHOUT ANY WARRANTY; without even the implied warranty of 12# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13# GNU General Public License for more details. 14# 15# You should have received a copy of the GNU General Public License 16# along with this program. If not, see <http://www.gnu.org/licenses/>. 17 18from collections import Counter 19 20from numpy import log, ndarray 21 22from .process import Process, ReversibleProcess, MichaelisMentenProcess, \ 23 RegulatedProcess, RegulatedMichaelisMentenProcess 24 25ProcessClasses = Process | ReversibleProcess | MichaelisMentenProcess | RegulatedProcess | RegulatedMichaelisMentenProcess 26 27 28def get_het_processes(processes: list[ProcessClasses, ...]) -> list[ProcessClasses, ...]: 29 """ 30 Filter the heterogeneous processes from a given list of processes. 31 A process is heterogeneous if any of its parameters are defined as such. 32 """ 33 het_procs = list() 34 35 for proc in processes: 36 if isinstance(proc, MichaelisMentenProcess): 37 if proc.is_heterogeneous or proc.is_heterogeneous_Km: 38 het_procs.append(proc) 39 elif isinstance(proc, RegulatedMichaelisMentenProcess): 40 if proc.is_heterogeneous or proc.is_heterogeneous_Km: 41 het_procs.append(proc) 42 else: 43 if isinstance(proc.regulating_species, list): # multiple regulators 44 if sum(proc.is_heterogeneous_K50) > 0: 45 het_procs.append(proc) 46 elif isinstance(proc.regulating_species, str): # only one regulator 47 if proc.is_heterogeneous_K50: 48 het_procs.append(proc) 49 elif isinstance(proc, RegulatedProcess): 50 if proc.is_heterogeneous: 51 het_procs.append(proc) 52 else: 53 if isinstance(proc.regulating_species, list): # multiple regulators 54 if sum(proc.is_heterogeneous_K50) > 0: 55 het_procs.append(proc) 56 elif isinstance(proc.regulating_species, str): # only one regulator 57 if proc.is_heterogeneous_K50: 58 het_procs.append(proc) 59 elif isinstance(proc, ReversibleProcess): 60 if proc.is_heterogeneous or proc.is_heterogeneous_rev: 61 het_procs.append(proc) 62 else: # isinstance(proc, Process) 63 if proc.is_heterogeneous: 64 het_procs.append(proc) 65 66 return het_procs 67 68 69def richness(arr: list | ndarray) -> int: 70 """ 71 Calculate the species richness, or how many subspecies 72 a species population comprises. 73 """ 74 return len(Counter(arr)) 75 76 77def idx_het(arr: list | ndarray) -> float: 78 """ 79 Calculate the Index of Heterogeneity (ψ), defined as the probability 80 that two randomly chosen agents (without replacement) from a species 81 population belong to different subspecies. 82 83 - A homogeneous population returns 0. 84 - A heterogeneous population with two distinct subspecies of equal 85 fractional abundance (χ=0.5) *approaches* 0.5 as the population 86 size increases. 87 - A fully heterogeneous population returns 1. 88 """ 89 ck = Counter(arr) # counter of k values 90 n_tot = len(arr) # total number of entries in sequence `arr` 91 92 s = 0 93 for v in ck.values(): 94 s += v * (v - 1) 95 96 try: 97 psi = 1 - s / (n_tot * (n_tot - 1)) 98 except ZeroDivisionError: 99 psi = 0 100 101 return psi 102 103 104def info_het(arr: list | ndarray) -> float: 105 """ 106 Information-theoretic measure of population heterogeneity. 107 108 - A homogeneous population returns 0. 109 - A heterogeneous population with two distinct subspecies of equal 110 fractional abundance (χ=0.5) returns ln(2). Note that this is 111 true regardless of the population size. 112 - For a fully heterogeneous population, the measure increases 113 with population size and has no upper limit. 114 """ 115 ck = Counter(arr) # counter of k values 116 n_tot = len(arr) # total number of agents 117 118 s = 0 119 120 for k, v in ck.items(): 121 chi = v / n_tot 122 s -= chi * log(chi) 123 124 return s
def
get_het_processes( processes: list[abstochkin.process.Process | abstochkin.process.ReversibleProcess | abstochkin.process.MichaelisMentenProcess | abstochkin.process.RegulatedProcess | abstochkin.process.RegulatedMichaelisMentenProcess, ...]) -> list[abstochkin.process.Process | abstochkin.process.ReversibleProcess | abstochkin.process.MichaelisMentenProcess | abstochkin.process.RegulatedProcess | abstochkin.process.RegulatedMichaelisMentenProcess, ...]:
29def get_het_processes(processes: list[ProcessClasses, ...]) -> list[ProcessClasses, ...]: 30 """ 31 Filter the heterogeneous processes from a given list of processes. 32 A process is heterogeneous if any of its parameters are defined as such. 33 """ 34 het_procs = list() 35 36 for proc in processes: 37 if isinstance(proc, MichaelisMentenProcess): 38 if proc.is_heterogeneous or proc.is_heterogeneous_Km: 39 het_procs.append(proc) 40 elif isinstance(proc, RegulatedMichaelisMentenProcess): 41 if proc.is_heterogeneous or proc.is_heterogeneous_Km: 42 het_procs.append(proc) 43 else: 44 if isinstance(proc.regulating_species, list): # multiple regulators 45 if sum(proc.is_heterogeneous_K50) > 0: 46 het_procs.append(proc) 47 elif isinstance(proc.regulating_species, str): # only one regulator 48 if proc.is_heterogeneous_K50: 49 het_procs.append(proc) 50 elif isinstance(proc, RegulatedProcess): 51 if proc.is_heterogeneous: 52 het_procs.append(proc) 53 else: 54 if isinstance(proc.regulating_species, list): # multiple regulators 55 if sum(proc.is_heterogeneous_K50) > 0: 56 het_procs.append(proc) 57 elif isinstance(proc.regulating_species, str): # only one regulator 58 if proc.is_heterogeneous_K50: 59 het_procs.append(proc) 60 elif isinstance(proc, ReversibleProcess): 61 if proc.is_heterogeneous or proc.is_heterogeneous_rev: 62 het_procs.append(proc) 63 else: # isinstance(proc, Process) 64 if proc.is_heterogeneous: 65 het_procs.append(proc) 66 67 return het_procs
Filter the heterogeneous processes from a given list of processes. A process is heterogeneous if any of its parameters are defined as such.
def
richness(arr: list | numpy.ndarray) -> int:
70def richness(arr: list | ndarray) -> int: 71 """ 72 Calculate the species richness, or how many subspecies 73 a species population comprises. 74 """ 75 return len(Counter(arr))
Calculate the species richness, or how many subspecies a species population comprises.
def
idx_het(arr: list | numpy.ndarray) -> float:
78def idx_het(arr: list | ndarray) -> float: 79 """ 80 Calculate the Index of Heterogeneity (ψ), defined as the probability 81 that two randomly chosen agents (without replacement) from a species 82 population belong to different subspecies. 83 84 - A homogeneous population returns 0. 85 - A heterogeneous population with two distinct subspecies of equal 86 fractional abundance (χ=0.5) *approaches* 0.5 as the population 87 size increases. 88 - A fully heterogeneous population returns 1. 89 """ 90 ck = Counter(arr) # counter of k values 91 n_tot = len(arr) # total number of entries in sequence `arr` 92 93 s = 0 94 for v in ck.values(): 95 s += v * (v - 1) 96 97 try: 98 psi = 1 - s / (n_tot * (n_tot - 1)) 99 except ZeroDivisionError: 100 psi = 0 101 102 return psi
Calculate the Index of Heterogeneity (ψ), 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.
def
info_het(arr: list | numpy.ndarray) -> float:
105def info_het(arr: list | ndarray) -> float: 106 """ 107 Information-theoretic measure of population heterogeneity. 108 109 - A homogeneous population returns 0. 110 - A heterogeneous population with two distinct subspecies of equal 111 fractional abundance (χ=0.5) returns ln(2). Note that this is 112 true regardless of the population size. 113 - For a fully heterogeneous population, the measure increases 114 with population size and has no upper limit. 115 """ 116 ck = Counter(arr) # counter of k values 117 n_tot = len(arr) # total number of agents 118 119 s = 0 120 121 for k, v in ck.items(): 122 chi = v / n_tot 123 s -= chi * log(chi) 124 125 return s
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.