Elements
Elements of systems: entities that carry states, and groups of identical elements.
BaseElement(label, visual=None)
Bases: BasePart[BaseSpace, SimpleNamespace]
Base of every element, a part of a system that holds states.
A subclass takes its states and parameters as arguments of its own __init__, annotated with Annotated and the
spec StateSpec or ParameterSpec, and stores each under its own name, as in scikit-learn. A subclass
drawn in its own way gives visual a default in its signature. It returns its laws from _get_laws, which every
subclass implements, returning an empty list when the element has none.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
label
|
str
|
The label of the element, unique among the parts of its system. |
required |
visual
|
VisualSpec | None
|
How the element is drawn, or |
None
|
Attributes:
| Name | Type | Description |
|---|---|---|
default_visual_ |
The visual of the element when it sets none. |
|
laws_ |
Sequence[BasePart]
|
The laws the element contributes for the namespace of its last run. |
Examples:
>>> from typing import Annotated
>>> from skcomplex.core.elements._base import BaseElement
>>> from skcomplex.specs import ParameterSpec, StateSpec
>>> from skcomplex.specs import VisualSpec
>>> class PopulationElement(BaseElement):
... def __init__(
... self,
... label,
... n: Annotated[float, StateSpec()] = 1.0,
... r: Annotated[float, ParameterSpec()] = 0.5,
... visual=VisualSpec('line'),
... ):
... super().__init__(label, visual=visual)
... self.n = n
... self.r = r
...
... def _get_laws(self, namespace):
... return []
>>> PopulationElement('rabbits', n=40).get_params(deep=False)
{'label': 'rabbits', 'n': 40, 'r': 0.5, 'visual': VisualSpec(kind='line', options={})}
Source code in src/skcomplex/core/elements/_base.py
70 71 72 | |
CompartmentElement(label, visual=None, *, n=0.0)
Bases: Element
Compartment, the amount of units in one named state, as a count or a fraction.
The label of the element names the compartment, such as 'A', 'B', or 'source'. A compartment has no laws
of its own, and reactions and flows between compartments move its units.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
label
|
str
|
The label of the compartment, unique among the parts of its system. |
required |
visual
|
VisualSpec | None
|
How the element is drawn, or |
None
|
n
|
Annotated[float, StateSpec(domain=closed_open(0, oo))]
|
The initial amount, a nonnegative count or fraction. |
0.0
|
Attributes:
| Name | Type | Description |
|---|---|---|
default_visual_ |
The visual of the element when it sets none. |
Examples:
>>> from skcomplex.core.elements import CompartmentElement
>>> from skcomplex.core.system import System
>>> from skcomplex.engine.runtime import Simulation
>>> system = System(elements=[CompartmentElement('A', n=990), CompartmentElement('B', n=10)])
>>> Simulation(system, dt=1.0).check().prepare().run(until=2).trajectory_.values('A.n').tolist()
[990.0, 990.0, 990.0]
Source code in src/skcomplex/core/elements/_compartment.py
44 45 46 47 48 49 50 51 52 | |
DensityElement(label, visual=None, *, f=0.0)
Bases: Element
Value of a density at one class, a member of a distribution over the classes.
A distribution is a group of densities on the sites of a lattice of classes, one member per class, and encounter, proliferation, and destruction laws change it. A density has no laws of its own.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
label
|
str
|
The label of the density, unique among the parts of its system. |
required |
visual
|
VisualSpec | None
|
How the element is drawn, or |
None
|
f
|
Annotated[float, StateSpec(domain=closed_open(0, oo))]
|
The initial density, a nonnegative number. |
0.0
|
Attributes:
| Name | Type | Description |
|---|---|---|
default_visual_ |
The visual of the element when it sets none. |
Examples:
>>> from skcomplex.core.elements import DensityElement, GroupElement
>>> from skcomplex.core.spaces import LatticeSpace
>>> classes = LatticeSpace(5, boundary='fixed')
>>> group = GroupElement('distribution', element=DensityElement, space=classes, on='sites', values={'f': 0.2})
>>> group.check().prepare().size_
5
Source code in src/skcomplex/core/elements/_density.py
44 45 46 47 48 49 50 51 52 | |
Element(label, visual=None)
Bases: BaseElement
Base class of entities that carry state, such as particles, populations, agents, or firms.
A subclass takes its states, its parameters, and visual as arguments of its own __init__, annotating each state
with a StateSpec and each parameter with a ParameterSpec inside Annotated, and returns its intrinsic dynamics
from _get_laws, which returns no laws by default. A subclass drawn in its own way gives visual a default in its
signature.
An element whose laws have the agent trait, such as rules, alone or in a group, is an agent: under discrete time it
runs on the agent stepper, whose rules receive every member as an agent with its states as attributes. Its states
then hold any value, not only numbers. A member is removed only when its states tagged with a quantity are settled
to zero, and its states and parameters cannot take the names of the agent view, such as location or alive, or
of the attributes Mesa reads, such as position or model.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
label
|
str
|
The label of the element, unique among the parts of its system. |
required |
visual
|
VisualSpec | None
|
How the element is drawn, or |
None
|
Attributes:
| Name | Type | Description |
|---|---|---|
default_visual_ |
The visual of the element when it sets none. |
Examples:
>>> from typing import Annotated
>>> from skcomplex.core.elements import Element
>>> from skcomplex.specs import StateSpec
>>> from skcomplex.specs import VisualSpec
>>> from sage.all__sagemath_symbolics import oo
>>> from sage.sets.real_set import RealSet
>>> class PopulationElement(Element):
... def __init__(
... self,
... label,
... n: Annotated[float, StateSpec(domain=RealSet.closed_open(0, oo))] = 1.0,
... visual=VisualSpec('line'),
... ):
... super().__init__(label, visual=visual)
... self.n = n
>>> PopulationElement('rabbits', n=40)
PopulationElement(label='rabbits', n=40)
Source code in src/skcomplex/core/elements/_base.py
70 71 72 | |
FieldElement(label, *, element, space, boundary=None, values=None, visual=None, discretization='finite-difference', symmetry=None)
Bases: LatticeElement
Group of members of one element type at the sites of a lattice, the nodes of a network, or a mesh.
The states of the members are fields, with one value per site, and the laws of the element type are written for
one site, with laplacian, gradient, divergence, and advection reading the neighbouring sites. Every state
takes a boundary condition at the edges of a lattice: 'periodic', 'zero-flux', or ('fixed', value), where
the value can be a function of the node coordinates on a mesh.
The discretization turns the operators into numbers. 'finite-difference' uses stencils on lattices and the graph
Laplacian on networks. 'spectral' multiplies Fourier modes on periodic lattices, with the two-thirds rule
removing aliasing. 'finite-volume' updates cell averages by the differences of the FluxLaws of the states.
'finite-element' assembles stiffness and mass matrices on a MeshSpace.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
label
|
str
|
The label of the field. |
required |
element
|
type[BaseElement]
|
The element type of the members. |
required |
space
|
LatticeSpace | NetworkSpace | MeshSpace
|
The lattice, the network, or the mesh. |
required |
boundary
|
Mapping[str, object] | None
|
A mapping from state name to its boundary condition, which overrides the edges of the lattice. The value of
|
None
|
values
|
Mapping[str, object] | None
|
Arrays of the lattice shape, or with one value per network node in node order, or shared values. |
None
|
visual
|
VisualSpec | None
|
How the field is drawn, or |
None
|
discretization
|
str
|
|
'finite-difference'
|
symmetry
|
Mapping[str, Sequence[object]] | None
|
A mapping from state name to its parity along every axis of a periodic lattice, |
None
|
Attributes:
| Name | Type | Description |
|---|---|---|
default_visual_ |
An image on a lattice, a colored mesh on a mesh, and on a network the visual of a member, or the sites of the network when the member sets none. |
|
size_ |
The number of sites of the space. |
|
values_ |
The values with one row per site, or one value shared by every site. |
Examples:
>>> from typing import Annotated
>>> from sage.all__sagemath_symbolics import var
>>> from skcomplex.core.elements import Element, FieldElement
>>> from skcomplex.core.laws import RateLaw
>>> from skcomplex.core.laws.utils import laplacian
>>> from skcomplex.core.spaces import LatticeSpace
>>> from skcomplex.specs import ParameterSpec, StateSpec
>>> class HeatElement(Element):
... def __init__(
... self, label, u: Annotated[float, StateSpec()] = 0.0, D: Annotated[float, ParameterSpec()] = 1.0
... ):
... super().__init__(label)
... self.u = u
... self.D = D
...
... def _get_laws(self, namespace):
... return [RateLaw(namespace.u, namespace.D * laplacian(namespace.u))]
>>> space = LatticeSpace((10, 20))
>>> plate = FieldElement('plate', element=HeatElement, space=space, boundary={'u': 'zero-flux'})
>>> plate.check().prepare().size_, plate.default_visual_.kind
(200, 'image')
Source code in src/skcomplex/core/elements/_field.py
100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 | |
GroupElement(label, *, element, size=None, values=None, visual=None, space=None, variable=False, on=None, location=None, layer=None, capacity=None)
Bases: BaseElement
Group of identical elements of one type, whose variables are arrays with one row per member.
A value is either an array whose first dimension is the size of the group, or one value shared by every member. Variables without a value take the default of the constructor of the element type, and the laws of the group are the laws of its element type, written for one member.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
label
|
str
|
The label of the group, unique among the children of its system. |
required |
element
|
type[BaseElement]
|
The element type of the members. |
required |
size
|
int | None
|
The number of members. |
None
|
values
|
Mapping[str, object] | None
|
A mapping from state or parameter name to its per-member or shared value. |
None
|
visual
|
VisualSpec | None
|
How the group is drawn, or |
None
|
space
|
BaseSpace | None
|
The space whose sites the members occupy, such as a lattice with one member per site, or |
None
|
variable
|
bool
|
Whether laws add and remove members during a run, such as the births and deaths of agents. |
False
|
on
|
str | None
|
The part of the space with one member each, |
None
|
location
|
object
|
The initial places of agents in the space: cell coordinates, a network node, or a position, one per member
or one shared by every member, or |
None
|
layer
|
str | None
|
The layer of the network whose edges a group on edges lives on, or |
None
|
capacity
|
int | None
|
The largest number of members of a variable group on the sites or edges of a network, which compiled
backends reserve rows for, or |
None
|
Attributes:
| Name | Type | Description |
|---|---|---|
default_visual_ |
The visual of a member, or the plain visual when the member sets none, which the group takes when it sets none. |
|
size_ |
The number of members: the size, or for a group on parts without one, the number of parts of its space. |
|
values_ |
The values with one row per member, or one value shared by every member. |
Examples:
>>> from typing import Annotated
>>> import networkx as nx
>>> from skcomplex.specs import StateSpec
>>> from skcomplex.core.elements import Element, GroupElement
>>> from skcomplex.core.spaces import NetworkSpace
>>> from skcomplex.specs import LayerSpec
>>> from skcomplex.specs import VisualSpec
>>> class PopulationElement(Element):
... def __init__(self, label, n: Annotated[float, StateSpec()] = 1.0, visual=VisualSpec('line')):
... super().__init__(label, visual=visual)
... self.n = n
>>> GroupElement('herds', element=PopulationElement, size=3).check().prepare().size_
3
>>> ring = NetworkSpace(nx.cycle_graph(30))
>>> GroupElement('weights', element=PopulationElement, space=ring, on='edges').check().prepare().size_
30
>>> space = NetworkSpace(nx.cycle_graph(4), layers=[LayerSpec('work', nx.complete_graph(4))])
>>> wages = GroupElement('wages', element=PopulationElement, space=space, on='edges', layer='work')
>>> wages.check().prepare().size_
6
>>> herds = GroupElement('herds', element=PopulationElement, size=3).check().prepare()
>>> herds.default_visual_
VisualSpec(kind='line', options={})
Source code in src/skcomplex/core/elements/_group.py
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 | |
LatticeElement(label, *, element, space, values=None, visual=None)
Bases: GroupElement
Group of elements with one member per site of a lattice or node of a network.
The laws of the element type are written for one cell, and local rules read the cells around it. Preparing turns values in the shape of the lattice, or mappings from node to value on a network, into one row per site.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
label
|
str
|
The label of the group, unique among the parts of its system. |
required |
element
|
type[BaseElement]
|
The element type of the cells. |
required |
space
|
BaseSpace
|
The lattice or other space of sites, or the network whose nodes are the sites, in the order of
|
required |
values
|
Mapping[str, object] | None
|
A mapping from state or parameter name to an array of the lattice shape, an array in node order, a mapping from node to value on a network, or a value shared by every cell. |
None
|
visual
|
VisualSpec | None
|
How the group is drawn, or |
None
|
Attributes:
| Name | Type | Description |
|---|---|---|
default_visual_ |
The visual of a member, or the default visual of the space when the member sets none, which the group takes when it sets none. |
|
size_ |
The number of sites of the space. |
|
values_ |
The values with one row per site, or one value shared by every site. |
Examples:
>>> from typing import Annotated
>>> import numpy as np
>>> from sage.sets.finite_enumerated_set import FiniteEnumeratedSet
>>> from skcomplex.core.elements import Element, LatticeElement
>>> from skcomplex.core.spaces import LatticeSpace
>>> from skcomplex.specs import StateSpec
>>> class CellElement(Element):
... def __init__(self, label, alive: Annotated[float, StateSpec(domain=FiniteEnumeratedSet([0, 1]))] = 0):
... super().__init__(label)
... self.alive = alive
>>> space = LatticeSpace((3, 4))
>>> cells = LatticeElement('cells', element=CellElement, space=space, values={'alive': np.eye(3, 4)})
>>> cells.check().prepare().size_, cells.values_['alive'].shape
(12, (12,))
Source code in src/skcomplex/core/elements/_lattice.py
68 69 70 71 72 73 74 75 76 77 | |
PointElement(label, x=0.0, x_d1=0.0, visual=None)
Bases: Element
Point of a continuous space, a member with a vector state x of order 2 that locates it.
The laws that act on the point give the second derivative of x, and the companion state x_d1 holds its first
derivative. The boundary of the space acts on x.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
label
|
str
|
The label of the point. |
required |
x
|
Annotated[ArrayLike, StateSpec(vector=True, order=2, role=position)]
|
The initial value of the vector state. A number applies to every component. |
0.0
|
x_d1
|
ArrayLike
|
The initial value of the first derivative of the vector state. A number applies to every component. |
0.0
|
visual
|
VisualSpec | None
|
How the point is drawn, or |
None
|
Attributes:
| Name | Type | Description |
|---|---|---|
default_visual_ |
Points at the values of |
Examples:
>>> from skcomplex.core.elements import PointElement
>>> from skcomplex.core.spaces import ContinuousSpace
>>> from skcomplex.core.system import System
>>> from skcomplex.engine.runtime import Simulation
>>> system = System(elements=[PointElement('ball', x_d1=[1.0, 0.0])], space=ContinuousSpace(n_dim=2))
>>> Simulation(system, dt=1.0).check().prepare().run(until=2.0).trajectory_.values('ball.x')[-1].tolist()
[2.0, 0.0]
Source code in src/skcomplex/core/elements/_point.py
48 49 50 51 52 53 54 55 56 57 | |