Exponential growth
A population that grows or declines at a constant per-capita rate.
- Name:
exponential_growth - Field:
biology/ecology - Formalism: ordinary differential equations
- References: Malthus 1798
Select this system
from skcomplex.systems import create_simulation, create_system, describe
system = create_system('exponential_growth')
entry = describe('exponential_growth')
trajectory = create_simulation('exponential_growth').prepare().run().trajectory_
Factory
@register_system(
field='biology/ecology',
tags=('population', 'ode'),
references=('Malthus 1798',),
defaults={'until': 20.0, 'dt': 0.1},
)
def exponential_growth(n: float = 10.0, r: float = 0.1) -> System:
"""Return a population that grows or declines at a constant per-capita rate.
Args:
n:
The initial size.
r:
The per-capita growth rate.
Returns:
system:
The system, with the population `population`.
Examples:
>>> from skcomplex.systems.biology.ecology import exponential_growth
>>> exponential_growth(r=0.2).interactions[0].r
0.2
"""
return System(
elements=[PopulationElement('population', n=n)],
interactions=[ExponentialGrowthInteraction('growth', target='population', r=r)],
)
Components
Elements:
PopulationElement, fromCompartmentElement
Interactions:
ExponentialGrowthInteraction, fromRateInteraction
class PopulationElement(CompartmentElement):
"""Population of one species, a compartment whose state `n` holds its size.
Args:
label:
The label of the population.
visual:
How the element is drawn, or `None` for `default_visual_`.
n:
The initial size.
Examples:
>>> from skcomplex.systems.biology.common.populations import PopulationElement
>>> PopulationElement('rabbits', n=40).n
40
"""
def __init__(
self,
label: str,
visual: VisualSpec | None = None,
*,
n: Annotated[float, StateSpec(domain=RealSet.closed_open(0, oo))] = 1.0,
) -> None:
super().__init__(label, visual=visual, n=n)
class ExponentialGrowthInteraction(GrowthInteraction):
"""Growth at a constant per capita rate, `dn/dt = r n`, the exponential form of a growth without harvest.
Args:
label:
The label of the interaction.
target:
The path of the element or group whose population grows.
r:
The per capita growth rate, negative for decay.
state:
The name of the state of the target that holds the population.
Examples:
>>> from skcomplex.core.components.elements import CompartmentElement
>>> from skcomplex.core.components.system import System
>>> from skcomplex.core.engine.runtime import Simulation
>>> from skcomplex.systems.biology.common.populations import ExponentialGrowthInteraction
>>> system = System(
... elements=[CompartmentElement('rabbits', n=1.0)],
... interactions=[ExponentialGrowthInteraction('growth', target='rabbits', r=0.5)],
... )
>>> trajectory = Simulation(system, dt=0.01).prepare().run(until=2.0).trajectory_
>>> round(float(trajectory.values('rabbits.n')[-1]), 3)
2.718
"""
def __init__(
self,
label: str,
*,
target: Annotated[str, RoleSpec()],
r: Annotated[float, ParameterSpec()] = 1.0,
state: str = 'n',
) -> None:
super().__init__(label, target=target, r=r, form='exponential', state=state)
def _get_rate(self, namespace: SimpleNamespace) -> Expression:
"""Return the growth `r n`, with no harvest.
Args:
namespace:
The namespace of the symbols the rate can use, with the namespace of the target.
Returns:
rate:
The rate of the population.
"""
return self._get_growth(namespace)
Equations
population.n: diff(n_population(t), t) == r_growth*n_population(t)