abstochkin.het_calcs API documentation

# abstochkin.het_calcs

Some functions for calculating metrics of population heterogeneity.

View Source

      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

ProcessClasses = abstochkin.process.Process | abstochkin.process.ReversibleProcess | abstochkin.process.MichaelisMentenProcess | abstochkin.process.RegulatedProcess | abstochkin.process.RegulatedMichaelisMentenProcess
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, ...]: View Source

    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: View Source

    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: View Source

     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: View Source

    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.