Skip to content

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 for default_visual_.

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
def __init__(self, label: str, visual: VisualSpec | None = None) -> None:
    super().__init__(label)
    self.visual = visual

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 for default_visual_.

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
def __init__(
    self,
    label: str,
    visual: VisualSpec | None = None,
    *,
    n: Annotated[float, StateSpec(domain=RealSet.closed_open(0, oo))] = 0.0,
) -> None:
    super().__init__(label, visual=visual)
    self.n = n

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 for default_visual_.

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
def __init__(
    self,
    label: str,
    visual: VisualSpec | None = None,
    *,
    f: Annotated[float, StateSpec(domain=RealSet.closed_open(0, oo))] = 0.0,
) -> None:
    super().__init__(label, visual=visual)
    self.f = f

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 for default_visual_.

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
def __init__(self, label: str, visual: VisualSpec | None = None) -> None:
    super().__init__(label)
    self.visual = visual

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 ('fixed', value) for a tensor state may be a matrix of the symmetry of the state.

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 for default_visual_.

None
discretization str

'finite-difference', 'spectral', 'finite-volume', or 'finite-element'.

'finite-difference'
symmetry Mapping[str, Sequence[object]] | None

A mapping from state name to its parity along every axis of a periodic lattice, 'odd', 'even', or None, which the rates keep exactly. A lattice twice as long as a domain along an axis, with states odd or even about its middle, represents walls there, such as the free-slip walls of convection. A vector or a tensor state takes one such sequence for its first component, or one sequence per component.

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
def __init__(
    self,
    label: str,
    *,
    element: type[BaseElement],
    space: LatticeSpace | NetworkSpace | MeshSpace,
    boundary: Mapping[str, object] | None = None,
    values: Mapping[str, object] | None = None,
    visual: VisualSpec | None = None,
    discretization: str = 'finite-difference',
    symmetry: Mapping[str, Sequence[object]] | None = None,
) -> None:
    super().__init__(label, element=element, space=space, values=values, visual=visual)
    self.boundary = boundary
    self.discretization = discretization
    self.symmetry = symmetry

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 for default_visual_.

None
space BaseSpace | None

The space whose sites the members occupy, such as a lattice with one member per site, or None for the space of the enclosing system.

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, 'sites', 'edges', or 'hyperedges', or None for members that are not tied to parts of the space. With a part and no size, the size is the number of parts.

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 for random places. Only the agent stepper reads it.

None
layer str | None

The layer of the network whose edges a group on edges lives on, or None for the graph of the network.

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 for twice the initial size.

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
def __init__(
    self,
    label: str,
    *,
    element: type[BaseElement],
    size: int | None = None,
    values: Mapping[str, object] | None = None,
    visual: VisualSpec | None = None,
    space: BaseSpace | None = None,
    variable: bool = False,
    on: str | None = None,
    location: object = None,
    layer: str | None = None,
    capacity: int | None = None,
) -> None:
    super().__init__(label, visual=visual)
    self.element = element
    self.size = size
    self.values = values
    self.space = space
    self.variable = variable
    self.on = on
    self.location = location
    self.layer = layer
    self.capacity = capacity

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 graph.nodes.

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 for default_visual_.

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
def __init__(
    self,
    label: str,
    *,
    element: type[BaseElement],
    space: BaseSpace,
    values: Mapping[str, object] | None = None,
    visual: VisualSpec | None = None,
) -> None:
    super().__init__(label, element=element, values=values, visual=visual, space=space, on='sites')

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 for default_visual_.

None

Attributes:

Name Type Description
default_visual_

Points at the values of x.

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
def __init__(
    self,
    label: str,
    x: Annotated[npt.ArrayLike, StateSpec(vector=True, order=2, role='position')] = 0.0,
    x_d1: npt.ArrayLike = 0.0,
    visual: VisualSpec | None = None,
) -> None:
    super().__init__(label, visual=visual)
    self.x = x
    self.x_d1 = x_d1