Undirected and directed polymer assembly pool
An assembly pool of linear polymers grown from one monomer by joining pairs of its polymers.
- Name:
polymer_assembly_pool - Field:
biology/evolution - Formalism: agent-based system
- References: Sharma et al. 2023
Select this system
from skcomplex.systems import create_simulation, create_system, describe
system = create_system('polymer_assembly_pool')
entry = describe('polymer_assembly_pool')
trajectory = create_simulation('polymer_assembly_pool').prepare().run().trajectory_
Factory
@register_system(
field='biology/evolution',
tags=('assembly theory', 'selection', 'polymers', 'agents'),
references=('Sharma et al. 2023',),
defaults={'until': 200},
)
def polymer_assembly_pool(mode: str = 'undirected', *, capacity: int = 2000) -> System:
"""Return an assembly pool of linear polymers grown from one monomer by joining pairs of its polymers.
Undirected exploration joins two random polymers of the pool, and directed exploration, a model of selection,
joins the newest polymer with a random one. Undirected joining fills the pool with many short polymers, while
directed joining builds ever longer chains, of a higher assembly index, about the base 2 logarithm of the length.
Args:
mode:
`'undirected'` or `'directed'`.
capacity:
The largest number of polymers the pool holds.
Returns:
system:
The system, with the lengths `pool.length` of the variable group `pool`.
Examples:
>>> from skcomplex.systems.biology.evolution import polymer_assembly_pool
>>> polymer_assembly_pool('directed').interactions[0].mode
'directed'
"""
pool = GroupElement('pool', element=PolymerElement, size=1, variable=True, capacity=capacity)
return System(
elements=[pool],
interactions=[PolymerJoiningInteraction('joining', polymers='pool', mode=mode)],
time=DiscreteTime(),
)
Components
Elements:
PolymerElement, fromElement
Interactions:
PolymerJoiningInteraction, fromInteraction
class PolymerElement(Element):
"""Linear polymer of an assembly pool, with its length and the step it was made.
Args:
label:
The label of the polymer or of the group of polymers.
visual:
How the element is drawn, or `None` for `default_visual_`.
length:
The number of monomers.
born:
The step at which the polymer was made.
Examples:
>>> from skcomplex.systems.biology.evolution import PolymerElement
>>> PolymerElement('polymer', length=3.0).length
3.0
"""
def __init__(
self,
label: str,
visual: VisualSpec | None = None,
*,
length: Annotated[float, StateSpec(domain=NN)] = 1.0,
born: Annotated[float, StateSpec(domain=NN)] = 0.0,
) -> None:
super().__init__(label, visual=visual)
self.length = length
self.born = born
@classmethod
def _get_view(cls) -> type[PolymerView]:
"""Return the view of a polymer, `PolymerView`."""
return PolymerView
class PolymerJoiningInteraction(Interaction):
"""Joining of two polymers of an assembly pool into a new one, at random or by reuse of the newest polymer.
At every step, undirected exploration joins two polymers drawn at random from the pool, and directed exploration
joins the polymer made most recently with one drawn at random. The joined polymer, of the summed length, is added
to the pool, and its parts stay in it.
Args:
label:
The label of the interaction.
polymers:
The path of the variable group of polymers.
mode:
`'undirected'` or `'directed'`.
Raises:
ValidationError:
The mode is unknown.
Examples:
>>> from skcomplex.systems.biology.evolution import PolymerJoiningInteraction
>>> PolymerJoiningInteraction('joining', polymers='pool', mode='directed').mode
'directed'
"""
def __init__(self, label: str, *, polymers: Annotated[str, RoleSpec()], mode: str = 'undirected') -> None:
super().__init__(label)
self.polymers = polymers
self.mode = mode
def _check(self) -> None:
"""Check the mode.
Raises:
ValidationError:
The mode is unknown.
"""
super()._check()
if self.mode not in MODES:
error_msg = f'The mode must be one of {", ".join(MODES)}, not {self.mode!r}.'
raise ValidationError(error_msg)
def _get_laws(self, s: SimpleNamespace) -> list[BaseLaw]:
"""Return the joining rule.
Args:
s:
The namespace of the symbols the laws can use.
Returns:
laws:
The laws of the component.
"""
return [RuleLaw(self.join)]
def join(self, system: SystemView) -> None:
"""Join two polymers and add the product to the pool.
Args:
system:
The system.
"""
pool = system.agents(self.polymers, PolymerView)
partner = pool[int(system.rng.integers(len(pool)))]
if self.mode == 'directed':
first = max(pool, key=lambda polymer: polymer.born)
else:
first = pool[int(system.rng.integers(len(pool)))]
born = max(polymer.born for polymer in pool) + 1
system.create(self.polymers, length=first.length + partner.length, born=born)