Skip to content

Specs

Define the specs: frozen values that declare, record, or hold what the classes of the library read.

AcceleratedSpec(rk4=None, velocity_verlet=None, yoshida4=None, euler_maruyama=None, gillespie=None, iterate=None) dataclass

Bases: BaseSpec

Compiled stepper loops of a problem, which run every internal step of a frame in compiled code.

Every loop takes (t, x, p, until, ...) and returns the state at until. A loop is None when the problem's form does not use it.

Parameters:

Name Type Description Default
rk4 Callable[..., Array] | None

The fourth-order Runge-Kutta loop rk4(t, x, p, until, h).

None
velocity_verlet Callable[..., Array] | None

The velocity Verlet loop velocity_verlet(t, x, p, until, h, positions, velocities).

None
yoshida4 Callable[..., Array] | None

The fourth-order Yoshida loop yoshida4(t, x, p, until, h, first, second, weights), which drifts the first block and kicks the second in every velocity Verlet stage of a weight.

None
euler_maruyama Callable[..., Array] | None

The Euler-Maruyama loop euler_maruyama(t, x, p, until, h, rng).

None
gillespie Callable[..., Array] | None

The Gillespie loop gillespie(t, x, p, until, rng).

None
iterate Callable[..., Array] | None

The discrete map loop iterate(t, x, p, until), or iterate(t, x, p, until, rng) for a stochastic map.

None

AgentSnapshotSpec(ids, values, locations=None, roles=dict()) dataclass

Bases: BaseSpec

Agents of one group alive at one frame.

Parameters:

Name Type Description Default
ids IntArray

The unique id of every agent.

required
values Mapping[str, AnyArray]

A mapping from state name to one value per agent.

required
locations AnyArray | None

One row per agent: grid coordinates, a network node, or a continuous position, or None without a space.

None
roles Mapping[str, str]

A mapping from the name of a state with a role to its role, 'position', 'direction', or 'velocity'.

dict()

AgentStateSpec(groups=dict(), reporters=dict()) dataclass

Bases: BaseSpec

Agents of every group and the model reporters at one frame.

Parameters:

Name Type Description Default
groups Mapping[str, AgentSnapshotSpec]

A mapping from group path to the agents of that group.

dict()
reporters Mapping[str, float]

A mapping from dotted reporter name to its value.

dict()

ArgumentsSpec(names=(), vectors=(), starts=(), sizes=()) dataclass

Bases: BaseSpec

Parameters and states that a lattice law reads besides its neighbourhoods, by name.

Parameters:

Name Type Description Default
names tuple[str, ...]

The keyword or symbol names.

()
vectors tuple[bool, ...]

Whether every argument is read from the state vector rather than the parameter vector.

()
starts tuple[int, ...]

The index of the first component of every argument.

()
sizes tuple[int, ...]

The number of components of every argument, the number of sites for per-site values or 1 for shared ones.

()

values(x, p, sites=None)

Return the values of the arguments, per-site values restricted to some sites.

Parameters:

Name Type Description Default
x Array

The state vector.

required
p Array

The parameter vector.

required
sites Indices | None

The sites to keep, or None for all.

None

Returns:

Name Type Description
values dict[str, Array | float]

The value of every argument by name.

Source code in src/skcomplex/specs/_arguments_spec.py
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
def values(self, x: Array, p: Array, sites: Indices | None = None) -> dict[str, Array | float]:
    """Return the values of the arguments, per-site values restricted to some sites.

    Args:
        x:
            The state vector.

        p:
            The parameter vector.

        sites:
            The sites to keep, or `None` for all.

    Returns:
        values:
            The value of every argument by name.
    """
    found: dict[str, Array | float] = {}
    for name, is_state, start, size in zip(self.names, self.vectors, self.starts, self.sizes, strict=True):
        source = x if is_state else p
        if size == 1:
            found[name] = float(source[start])
            continue
        values = source[start : start + size]
        found[name] = values if sites is None else values[sites]
    return found

AxisSpec(name, size, low, high, periodic=False) dataclass

Bases: BaseSpec

Spec of a class axis of a phase space, a uniform grid of cells over a range of values.

Parameters:

Name Type Description Default
name str

The name of the axis, which laws read its coordinate by.

required
size int

The number of cells.

required
low float

The lower end of the range.

required
high float

The upper end of the range.

required
periodic bool

Whether the two ends of the range are joined, as for an angle, rather than edges without flux.

False

Examples:

>>> from skcomplex.specs import AxisSpec
>>> AxisSpec('v', 128, -6.0, 6.0).check().name
'v'

BaseRecordSpec() dataclass

Bases: BaseSpec

Base of the records: something that happened at one time of a run, such as an event or a cascade.

Every record has the readers label, the name of what happened, and time, the time it happened at.

BaseSpec() dataclass

Bases: BaseConfig

Base of every spec: a frozen dataclass whose fields are what it is and whose check() validates them.

A spec declares what a class reads, records what a run produced, or holds what a compiler built. It never changes, holds only its fields, check(), and readers of its own fields, and is prepared and run like any configurable object, both doing nothing. It is the only base whose hooks have defaults: a child that validates its fields overrides _check().

Examples:

>>> from dataclasses import dataclass
>>> from skcomplex.specs import BaseSpec
>>> @dataclass(frozen=True)
... class SpanSpec(BaseSpec):
...     start: float
...     end: float
>>> SpanSpec(0.0, 1.0).check().end
1.0

check()

Validate the fields of the spec.

Returns:

Name Type Description
self Self

The spec.

Raises:

Type Description
ValidationError

A field is invalid, named in the message.

Source code in src/skcomplex/specs/_base_spec.py
47
48
49
50
51
52
53
54
55
56
57
58
59
def check(self) -> Self:
    """Validate the fields of the spec.

    Returns:
        self:
            The spec.

    Raises:
        ValidationError:
            A field is invalid, named in the message.
    """
    self._check()
    return self

prepare(context=None)

Prepare the spec, which a value leaves as it is.

Parameters:

Name Type Description Default
context object | None

What the spec serves, which a spec does not read.

None

Returns:

Name Type Description
self Self

The spec.

Source code in src/skcomplex/specs/_base_spec.py
61
62
63
64
65
66
67
68
69
70
71
72
73
def prepare(self, context: object | None = None) -> Self:
    """Prepare the spec, which a value leaves as it is.

    Args:
        context:
            What the spec serves, which a spec does not read.

    Returns:
        self:
            The spec.
    """
    self._prepare(context)
    return self

BaseStructureSpec() dataclass

Bases: BaseSpec

Base of the structures of a rewriting element at one generation: a word, a patch of tiles, or a graph.

The readers parts, segments, polygons, geometry, and raster describe the structure; subclasses give the parts, the segments, and the polygons, and the measures follow from them with Shapely. Every subclass has the field generation, and its arrays are read-only, built with _frozen, so later generations cannot change a recorded structure.

has_geometry property

Whether the structure has a geometry, a patch or a word with a word geometry.

parts property

Number of parts, symbols, tiles, or nodes.

area()

Return the total area of the polygons.

Returns:

Name Type Description
area float

The sum of the areas of the polygons, 0 without polygons.

Source code in src/skcomplex/specs/_base_structure_spec.py
88
89
90
91
92
93
94
95
def area(self) -> float:
    """Return the total area of the polygons.

    Returns:
        area:
            The sum of the areas of the polygons, 0 without polygons.
    """
    return float(shapely.area(self.geometry()).sum())

bounds()

Return the bounding box of the geometry in the plane.

Returns:

Name Type Description
bounds tuple[float, float, float, float]

(xmin, ymin, xmax, ymax), or zeros without geometry.

Source code in src/skcomplex/specs/_base_structure_spec.py
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
def bounds(self) -> tuple[float, float, float, float]:
    """Return the bounding box of the geometry in the plane.

    Returns:
        bounds:
            `(xmin, ymin, xmax, ymax)`, or zeros without geometry.
    """
    geometry = self.geometry()
    if not len(geometry):
        return (0.0, 0.0, 0.0, 0.0)
    box = shapely.bounds(geometry)
    return (
        float(box[:, 0].min()),
        float(box[:, 1].min()),
        float(box[:, 2].max()),
        float(box[:, 3].max()),
    )

geometry()

Return the segments and polygons as an array of Shapely geometries.

Returns:

Name Type Description
geometry AnyArray

The line strings of the segments followed by the polygons.

Source code in src/skcomplex/specs/_base_structure_spec.py
59
60
61
62
63
64
65
66
def geometry(self) -> AnyArray:
    """Return the segments and polygons as an array of Shapely geometries.

    Returns:
        geometry:
            The line strings of the segments followed by the polygons.
    """
    return self._geometry

length()

Return the total length of the segments and the perimeters of the polygons.

Returns:

Name Type Description
length float

The total length.

Source code in src/skcomplex/specs/_base_structure_spec.py
76
77
78
79
80
81
82
83
84
85
86
def length(self) -> float:
    """Return the total length of the segments and the perimeters of the polygons.

    Returns:
        length:
            The total length.
    """
    segments = np.asarray(self.segments(), dtype=float)
    if segments.shape[-1] == SPACE_DIMENSIONS:
        return float(np.linalg.norm(segments[:, 1] - segments[:, 0], axis=-1).sum())
    return float(shapely.length(self.geometry()).sum())

polygons()

Return the polygons of the geometry, one coordinate array of shape (t, k, 2) per vertex count k.

Returns:

Name Type Description
polygons AnyArray

An object array of coordinate arrays, empty without polygons.

Source code in src/skcomplex/specs/_base_structure_spec.py
50
51
52
53
54
55
56
57
def polygons(self) -> AnyArray:
    """Return the polygons of the geometry, one coordinate array of shape `(t, k, 2)` per vertex count `k`.

    Returns:
        polygons:
            An object array of coordinate arrays, empty without polygons.
    """
    return np.zeros(0, dtype=object)

raster(resolution, bounds=None)

Return a square boolean grid of the cells the geometry covers, with the first row at the top.

Segments mark the cells of points spaced at most half a cell apart along them, and polygons mark the cells whose centres they contain, so the grid suits ScalingAnalysis('box-counting').

Parameters:

Name Type Description Default
resolution int

The number of cells per side.

required
bounds Sequence[float] | None

The box (xmin, ymin, xmax, ymax) to rasterise, or None for the bounding box of the geometry. The grid covers a square with the longer side of the box.

None

Returns:

Name Type Description
grid NDArray[bool_]

The boolean grid of shape (resolution, resolution).

Raises:

Type Description
ValidationError

The resolution is not a positive integer.

Source code in src/skcomplex/specs/_base_structure_spec.py
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
def raster(self, resolution: int, bounds: Sequence[float] | None = None) -> npt.NDArray[np.bool_]:
    """Return a square boolean grid of the cells the geometry covers, with the first row at the top.

    Segments mark the cells of points spaced at most half a cell apart along them, and polygons mark the cells
    whose centres they contain, so the grid suits `ScalingAnalysis('box-counting')`.

    Args:
        resolution:
            The number of cells per side.

        bounds:
            The box `(xmin, ymin, xmax, ymax)` to rasterise, or `None` for the bounding box of the geometry. The
            grid covers a square with the longer side of the box.

    Returns:
        grid:
            The boolean grid of shape `(resolution, resolution)`.

    Raises:
        ValidationError:
            The resolution is not a positive integer.
    """
    if not isinstance(resolution, int | np.integer) or resolution < 1:
        error_msg = f'resolution = {resolution!r} must be a positive integer.'
        raise ValidationError(error_msg)
    xmin, ymin, xmax, ymax = self.bounds() if bounds is None else bounds
    side = max(xmax - xmin, ymax - ymin) or 1.0
    cell = side / resolution
    grid = np.zeros((resolution, resolution), dtype=bool)
    geometry = self.geometry()
    if not len(geometry):
        return grid
    lines = geometry[shapely.get_type_id(geometry) == shapely.GeometryType.LINESTRING]
    if len(lines):
        points = shapely.get_coordinates(shapely.segmentize(lines, cell / 2))
        self._mark(grid, points, xmin, ymax, cell)
    shapes = geometry[shapely.get_type_id(geometry) == shapely.GeometryType.POLYGON]
    if len(shapes):
        centres = (np.arange(resolution) + 0.5) * cell
        x, y = np.meshgrid(xmin + centres, ymax - centres)
        tree = shapely.STRtree(shapes)
        found = tree.query(shapely.points(x.ravel(), y.ravel()), predicate='intersects')[0]
        grid.ravel()[np.unique(found)] = True
    return grid

segments()

Return the line segments of the geometry.

Returns:

Name Type Description
segments AnyArray

The array of shape (k, 2, d), empty without segments.

Source code in src/skcomplex/specs/_base_structure_spec.py
41
42
43
44
45
46
47
48
def segments(self) -> AnyArray:
    """Return the line segments of the geometry.

    Returns:
        segments:
            The array of shape `(k, 2, d)`, empty without segments.
    """
    return np.zeros((0, 2, 2))

BatchMatchingSpec() dataclass

Bases: BaseSpec

Batch matching that collects every offer, then matches the largest quantity at one clearing value.

Requesters are sorted by decreasing and providers by increasing limit, and they are paired while the requester's limit covers the provider's. The value is the midpoint of the last paired limits, and every paired requester and provider matches at it.

Examples:

>>> from skcomplex.specs import BatchMatchingSpec
>>> BatchMatchingSpec().check()
BatchMatchingSpec()

CallSpec(function, arguments=(), relative=False, random=False, vectorized=False) dataclass

Bases: BaseSpec

Law value computed by a function of time and scalar arguments, called once per member or pair.

The Numba backend calls a Numba-compiled function inside its compiled kernels, and the NumPy backend calls any function from Python. The function returns a number for a scalar target, or one number per component for a vector target. A law that sets relative, random, or vectorized runs in Python on every backend.

Parameters:

Name Type Description Default
function object

The function f(t, *arguments), or f(t, values) when arguments is None or relative is true.

required
arguments tuple[object, ...] | None

The symbolic expressions whose values are passed to the function, or None to pass the mapping from the dotted name of every state and parameter to its value.

()
relative bool

Whether to pass the mapping with the names of the component of the law, such as x for a state of the element itself and target.x for a state of the element bound to the role target. Those names do not depend on the label of the component or the system that holds it. It takes no arguments.

False
random bool

Whether to pass the random stream of the simulation as the keyword argument rng, so that one seed repeats the run.

False
vectorized bool

Whether to call the function once per evaluation with one array per argument, instead of once per member or pair. It returns one value, or one value per member or pair.

False

Examples:

>>> from sage.all__sagemath_symbolics import var
>>> from skcomplex.specs import CallSpec
>>> n = var('n')
>>> CallSpec(lambda t, n: 2 * n, (n,)).arguments
(n,)
>>> CallSpec(lambda t, values: values['n'], relative=True).check().relative
True

CapacityRowsSpec(path, variables, defaults, active, source=None, target=None, members=None) dataclass

Bases: BaseSpec

Rows of a variable group on the nodes, edges, or hyperedges of a network, with the values of a new member.

Parameters:

Name Type Description Default
path str

The path of the group.

required
variables Mapping[str, tuple[EntrySpec, bool]]

The entry of every state and parameter of the members by name, with whether it is a state.

required
defaults Mapping[str, Array]

The flat values of one new member of every variable by name.

required
active EntrySpec

The parameter entry of the activity of every row.

required
source EntrySpec | None

The parameter entry of the source node of every edge row, or None for a group on the nodes.

None
target EntrySpec | None

The parameter entry of the target node of every edge row, or None for a group on the nodes.

None
members EntrySpec | None

The parameter entry of the member nodes of every hyperedge row, one column per member, or None for a group on the nodes or edges.

None

ends(p)

Return the source and target node of every edge row.

Parameters:

Name Type Description Default
p Array

The parameter vector.

required

Returns:

Name Type Description
ends tuple[Indices, Indices]

The source and target node rows.

Source code in src/skcomplex/specs/_capacity_rows_spec.py
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
def ends(self, p: Array) -> tuple[Indices, Indices]:
    """Return the source and target node of every edge row.

    Args:
        p:
            The parameter vector.

    Returns:
        ends:
            The source and target node rows.
    """
    assert self.source is not None
    assert self.target is not None
    return self.source.view(p)[:, 0].astype(np.intp), self.target.view(p)[:, 0].astype(np.intp)

hyperedges(p)

Return the member nodes of every hyperedge row.

Parameters:

Name Type Description Default
p Array

The parameter vector.

required

Returns:

Name Type Description
members Indices

One row of member nodes per hyperedge row.

Source code in src/skcomplex/specs/_capacity_rows_spec.py
108
109
110
111
112
113
114
115
116
117
118
119
120
def hyperedges(self, p: Array) -> Indices:
    """Return the member nodes of every hyperedge row.

    Args:
        p:
            The parameter vector.

    Returns:
        members:
            One row of member nodes per hyperedge row.
    """
    assert self.members is not None
    return self.members.view(p).astype(np.intp)

present(p)

Return whether every row holds a member.

Parameters:

Name Type Description Default
p Array

The parameter vector.

required

Returns:

Name Type Description
present NDArray[bool_]

One flag per row.

Source code in src/skcomplex/specs/_capacity_rows_spec.py
56
57
58
59
60
61
62
63
64
65
66
67
def present(self, p: Array) -> npt.NDArray[np.bool_]:
    """Return whether every row holds a member.

    Args:
        p:
            The parameter vector.

    Returns:
        present:
            One flag per row.
    """
    return self.active.view(p)[:, 0] > ACTIVE_THRESHOLD

take_row(p)

Return the first free row.

Parameters:

Name Type Description Default
p Array

The parameter vector.

required

Returns:

Name Type Description
row int

The row.

Raises:

Type Description
CapacityError

Every row holds a member.

Source code in src/skcomplex/specs/_capacity_rows_spec.py
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
def take_row(self, p: Array) -> int:
    """Return the first free row.

    Args:
        p:
            The parameter vector.

    Returns:
        row:
            The row.

    Raises:
        CapacityError:
            Every row holds a member.
    """
    free = np.flatnonzero(~self.present(p))
    if not free.size:
        error_msg = (
            f'The group {self.path} holds {self.active.rows} members, its capacity, and a topology request adds '
            'another. Give the group a larger capacity, `GroupElement(..., variable=True, capacity=n)`.'
        )
        raise CapacityError(error_msg)
    return int(free[0])

CardinalitySpec(literals, bound, sense='at-least') dataclass

Bases: BaseSpec

Constraint that at least or at most a bound of its literals hold.

A literal is a member index from 1, negative for its negation.

Parameters:

Name Type Description Default
literals Sequence[int]

The literals of the constraint.

required
bound int

The number of literals that bounds those that hold.

required
sense str

'at-least' or 'at-most'.

'at-least'

Raises:

Type Description
ValidationError

A literal is 0, the bound lies outside the number of literals, or the sense is unknown, raised by check.

Examples:

>>> from skcomplex.specs import CardinalitySpec
>>> CardinalitySpec((1, -2, 3), 2).check().sense
'at-least'

CascadeRecordSpec(label, time, size, duration, area) dataclass

Bases: BaseRecordSpec

Cascade of a lattice within one step, such as an avalanche.

Parameters:

Name Type Description Default
label str

The label of the cascade.

required
time float

The time of the step.

required
size int

The number of site updates.

required
duration int

The number of iterations of the cascade.

required
area int

The number of distinct sites that changed.

required

ClampSpec(max_angle=None, min_norm=None, max_norm=None) dataclass

Bases: BaseSpec

Clamp of the change of a vector, by the largest angle it turns and the bounds of its norm.

Every bound is a number, the name of a parameter of the agent, or None for no bound. The vector turns from its current direction toward its new one by at most max_angle, keeping the new norm, and its norm is then clipped between min_norm and max_norm. A zero vector stays zero.

Parameters:

Name Type Description Default
max_angle float | str | None

The largest angle in radians the vector turns, or None.

None
min_norm float | str | None

The smallest norm, or None.

None
max_norm float | str | None

The largest norm, or None.

None

Raises:

Type Description
ValidationError

A bound is negative, raised by check.

Examples:

>>> from skcomplex.specs import ClampSpec
>>> ClampSpec(min_norm=0.5, max_norm='speed').check().max_norm
'speed'

ClauseSpec(literals) dataclass

Bases: BaseSpec

Disjunction of literals, where a literal is a member index from 1, negative for its negation.

Parameters:

Name Type Description Default
literals Sequence[int]

The literals of the clause.

required

Raises:

Type Description
ValidationError

A literal is 0 or the clause holds none, raised by check.

Examples:

>>> from skcomplex.specs import ClauseSpec
>>> ClauseSpec((1, -2)).check().literals
(1, -2)

ContinuousMatchingSpec(arrival='random') dataclass

Bases: BaseSpec

Continuous matching by limit and arrival, in which every arriving offer matches the best resting offers.

Every participant submits one offer, in random order of arrival or in order of creation. An arriving offer matches the best offers of the other side, the oldest first among equal limits, at their limits, as long as the limits cross, and its remainder rests. The resting offers are dropped at the end of every matching (Caiani et al. 2016 ch. 3).

Parameters:

Name Type Description Default
arrival str

The order of arrival, 'random' or 'sequential'.

'random'

Raises:

Type Description
ValidationError

The order of arrival is unknown, raised by check.

Examples:

>>> from skcomplex.specs import ContinuousMatchingSpec
>>> ContinuousMatchingSpec().check().arrival
'random'

ControlSolutionSpec(times, states, costates, cost, iterations) dataclass

Bases: BaseSpec

Optimal control of a run over its horizon, sampled on a grid of times.

Parameters:

Name Type Description Default
times Array

The times of the grid, from the start to the horizon.

required
states Array

The state vector at every time of the grid, with the controls at their optimal values, one row per time.

required
costates Mapping[str, Array]

The costate of every state the controls steer, by state name, one value per time, or empty when the solver does not compute costates.

required
cost float

The value of the objective, the running value integrated over the run plus the terminal value.

required
iterations int

The number of sweeps or optimiser iterations the solver took.

required

state_at(t)

Return the state vector at a time of the run, interpolated linearly between the times of the grid.

Parameters:

Name Type Description Default
t float

The time.

required

Returns:

Name Type Description
state Array

The state vector.

Source code in src/skcomplex/specs/_control_solution_spec.py
43
44
45
46
47
48
49
50
51
52
53
54
def state_at(self, t: float) -> Array:
    """Return the state vector at a time of the run, interpolated linearly between the times of the grid.

    Args:
        t:
            The time.

    Returns:
        state:
            The state vector.
    """
    return np.array([np.interp(t, self.times, column) for column in self.states.T])

CovarianceAdaptationSpec(sigma=0.1) dataclass

Bases: BaseSpec

Settings of covariance matrix adaptation.

Parameters:

Name Type Description Default
sigma float

The initial step size, relative to the box of the candidates.

0.1

Examples:

>>> from skcomplex.specs import CovarianceAdaptationSpec
>>> CovarianceAdaptationSpec().check().sigma
0.1

DatasetSpec(values, weights=None, times=None) dataclass

Bases: BaseSpec

Sequences of values of the parameters of a model, one value per sequence and inner step, with step weights.

Every array has the shape (sequences, steps) followed by the shape of its parameter. At inner step k of sequence i every parameter takes its value at [i, k] before the laws of the step are evaluated, as a schedule sets a parameter in a simulation, and the loss reads the states the step gives. Every sequence starts from the initial states of the model.

Parameters:

Name Type Description Default
values Mapping[str, AnyArray]

A mapping from the dotted path of a parameter of the model, such as inputs.x, to its values.

required
weights AnyArray | Mapping[str, AnyArray] | None

The weights of the steps in the loss and in every metric, an array of shape (sequences, steps), a mapping from the label of the loss or of a metric to such an array, the others weighting every step equally, or None for equal weights.

None
times AnyArray | None

The times of the ends of the inner steps of a model of ordinary differential equations, one per step and increasing from a positive time, since the run starts at time 0, or None for the times 1, 2, ....

None

Raises:

Type Description
ValidationError

The values are empty, a path is not a string, or an array has fewer than two dimensions.

Examples:

>>> import numpy as np
>>> from skcomplex.specs import DatasetSpec
>>> data = DatasetSpec({'inputs.x': np.zeros((5, 12, 1))}).check()
>>> data.sequences, data.steps
(5, 12)

sequences property

Number of sequences, the length of the first axis of the first array.

steps property

Number of inner steps of every sequence, the length of the second axis of the first array.

DialectSpec(name, functions, relations, power='**', error=ValidationError, exact_rationals=False, complex_numbers=False, folds=(lambda: frozenset({'min', 'max', 'either', 'both'}))()) dataclass

Bases: BaseSpec

Syntax of a target language for printed expressions.

Templates take their arguments as {0}, {1}, and so on, receive every argument that is not an atom in parentheses, and must give an atom, a name, a call, or a parenthesized expression.

Parameters:

Name Type Description Default
name str

The name of the language, used in error messages.

required
functions Mapping[str, str]

A mapping from Sage function names to templates.

required
relations Mapping[str, str]

A mapping from lt, le, gt, ge, eq, and ne to templates.

required
power str

The power operator.

'**'
error type[Exception]

The error raised for an expression the language cannot express.

ValidationError
exact_rationals bool

Whether rationals print as divisions of integers instead of floating point literals.

False
complex_numbers bool

Whether complex numbers print as Python complex literals instead of raising an error.

False

unknown(name)

Return the error of an expression the language cannot express.

Parameters:

Name Type Description Default
name str

The name of the function or expression.

required

Returns:

Name Type Description
error Exception

The error.

Source code in src/skcomplex/specs/_dialect_spec.py
61
62
63
64
65
66
67
68
69
70
71
72
73
def unknown(self, name: str) -> Exception:
    """Return the error of an expression the language cannot express.

    Args:
        name:
            The name of the function or expression.

    Returns:
        error:
            The error.
    """
    error_msg = f'The function {name} has no {self.name} equivalent. Write the law with the functions it supports.'
    return self.error(error_msg)

DifferentialEvolutionSpec(variant='DE/best/1/bin', weight=0.5, crossover=0.2) dataclass

Bases: BaseSpec

Settings of differential evolution.

Parameters:

Name Type Description Default
variant str

The scheme of pymoo's differential evolution, such as 'DE/best/1/bin', its default.

'DE/best/1/bin'
weight float

The differential weight of the mutation, by default that of pymoo.

0.5
crossover float

The crossover probability, by default that of pymoo.

0.2

Examples:

>>> from skcomplex.specs import DifferentialEvolutionSpec
>>> DifferentialEvolutionSpec().check().variant
'DE/best/1/bin'

DirectionSpec(entry, angle) dataclass

Bases: BaseSpec

State that holds the direction of the members, a vector or an angle in two dimensions.

Parameters:

Name Type Description Default
entry EntrySpec

The entry of the state.

required
angle bool

Whether the state is a scalar angle, whose direction is (cos, sin).

required

vectors(x)

Return the direction of every member as one row of components.

Parameters:

Name Type Description Default
x Array

The state vector.

required

Returns:

Name Type Description
directions Array

One row per member.

Source code in src/skcomplex/specs/_direction_spec.py
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
def vectors(self, x: Array) -> Array:
    """Return the direction of every member as one row of components.

    Args:
        x:
            The state vector.

    Returns:
        directions:
            One row per member.
    """
    values = self.entry.view(x)
    if self.angle:
        return np.column_stack([np.cos(values[:, 0]), np.sin(values[:, 0])])
    return values

DrawSpec(kind, name, distribution=None, keywords=(), arguments=(), call=None) dataclass

Bases: BaseSpec

Random draw: its kind, its name, and, for a distribution of scipy.stats, the distribution and its keywords.

Parameters:

Name Type Description Default
kind str

'uniform', 'normal', 'bernoulli', 'categorical', or 'draw' for a distribution of scipy.stats.

required
name str

The name of the draw.

required
distribution str | None

The name of the scipy.stats distribution of a draw of kind 'draw', or None.

None
keywords tuple[str, ...]

The keyword of every argument of a draw of kind 'draw'.

()
arguments tuple[Expression, ...]

The arguments of the distribution in a call, empty for the draw of a function.

()
call Expression | None

The symbolic call of the draw in the expression it was found in, or None for the draw of a function.

None

Examples:

>>> from skcomplex.core.laws.utils import bernoulli, draws_in
>>> draws_in(bernoulli('flip', 0.5))[0].kind
'bernoulli'

parameters property

Arguments of a draw from a scipy.stats distribution by keyword.

EntrySpec(name, start, shape, domain, members=None, is_complex=False, period=None, tensor=None) dataclass

Bases: BaseSpec

Position of one named variable in a flat vector.

Parameters:

Name Type Description Default
name str

The dotted name of the variable, such as meadow/rabbits.n.

required
start int

The index of the first component in the vector.

required
shape tuple[int, ...]

The shape of the variable, () for a scalar and (n_dim,) for a vector.

required
domain object

The Sage set of the values the variable takes.

required
members int | None

The size of the group that holds the variable, or None for a single element or an interaction.

None
is_complex bool

Whether the variable is complex, with the real and imaginary part of every component stored in a row.

False
period float | None

The period that values of the variable wrap around, or None.

None
tensor TensorSpec | None

The independent components of a rank-2 tensor variable, or None.

None

Examples:

>>> from sage.all__sagemath_symbolics import CC, RR
>>> from skcomplex.specs import EntrySpec
>>> entry = EntrySpec('a.z', 0, (2,), CC, is_complex=True)
>>> entry.size, entry.component_names
(4, ['a.z[0].real', 'a.z[0].imag', 'a.z[1].real', 'a.z[1].imag'])
>>> from skcomplex.specs import TensorSpec
>>> tensor = EntrySpec('a.Q', 0, (2,), RR, tensor=TensorSpec('traceless', 2))
>>> tensor.component_names, tensor.kind.value
(['a.Q_xx', 'a.Q_xy'], 'tensor')

columns cached property

Number of components of the variable of one member.

component_names property

Names of the components, with an index suffix for vectors, a member index for groups, and complex parts.

generic_names property

Names of the components of one member, with the member index i for groups.

indices cached property

Slice of the variable's components in the vector.

kind property

Kind of value the variable takes, an angle for a periodic variable and a tensor for a tensor component.

member_shape property

Shape of the variable of one member, () for a scalar and (n_dim,) for a vector.

rows cached property

Number of members, 1 for a single element or an interaction.

size cached property

Number of components of the variable.

contains(value)

Check that every component of a value belongs to the domain of the variable.

Parameters:

Name Type Description Default
value object

A value or an array of values.

required

Returns:

Name Type Description
is_contained bool

Whether every component belongs to the domain.

Source code in src/skcomplex/specs/_entry_spec.py
203
204
205
206
207
208
209
210
211
212
213
214
def contains(self, value: object) -> bool:
    """Check that every component of a value belongs to the domain of the variable.

    Args:
        value:
            A value or an array of values.

    Returns:
        is_contained:
            Whether every component belongs to the domain.
    """
    return EntrySpec._contains(self.domain, value)

decode(values)

Return the stored components of the variable, the last axis of an array, with complex parts joined.

Parameters:

Name Type Description Default
values Array

The stored components on the last axis.

required

Returns:

Name Type Description
values Array | ComplexArray

The values, complex for a complex variable, with the last axis of the shape of the variable.

Source code in src/skcomplex/specs/_entry_spec.py
181
182
183
184
185
186
187
188
189
190
191
192
193
194
def decode(self, values: Array) -> Array | ComplexArray:
    """Return the stored components of the variable, the last axis of an array, with complex parts joined.

    Args:
        values:
            The stored components on the last axis.

    Returns:
        values:
            The values, complex for a complex variable, with the last axis of the shape of the variable.
    """
    if not self.is_complex:
        return values
    return np.ascontiguousarray(values).view(complex)

encode(value)

Return a value broadcast to the shape of the variable as flat floats, in pairs for a complex variable.

Parameters:

Name Type Description Default
value object

A value in the domain of the variable, of its shape or of a shape that broadcasts to it.

required

Returns:

Name Type Description
components NDArray[float64]

The flat components, as stored in a vector.

Raises:

Type Description
ValueError

The value does not broadcast to the shape of the variable.

Examples:

>>> from sage.all__sagemath_symbolics import CC, RR
>>> from skcomplex.specs import EntrySpec
>>> EntrySpec('a.z', 0, (), CC, is_complex=True).encode(1 + 2j).tolist()
[1.0, 2.0]
Source code in src/skcomplex/specs/_entry_spec.py
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
def encode(self, value: object) -> npt.NDArray[np.float64]:
    """Return a value broadcast to the shape of the variable as flat floats, in pairs for a complex variable.

    Args:
        value:
            A value in the domain of the variable, of its shape or of a shape that broadcasts to it.

    Returns:
        components:
            The flat components, as stored in a vector.

    Raises:
        ValueError:
            The value does not broadcast to the shape of the variable.

    Examples:
        >>> from sage.all__sagemath_symbolics import CC, RR
        >>> from skcomplex.specs import EntrySpec
        >>> EntrySpec('a.z', 0, (), CC, is_complex=True).encode(1 + 2j).tolist()
        [1.0, 2.0]
    """
    values = np.broadcast_to(EntrySpec._encode(self.domain, value, self.period), self.shape)
    if self.is_complex:
        return np.ascontiguousarray(values, dtype=complex).ravel().view(float).copy()
    return values.ravel().copy()

read(values)

Return stored numbers as values of the domain: labels for a categorical domain, booleans for a boolean one.

Parameters:

Name Type Description Default
values ArrayLike

The stored numbers.

required

Returns:

Name Type Description
values NDArray[generic]

The values.

Examples:

>>> from sage.sets.finite_enumerated_set import FiniteEnumeratedSet
>>> from skcomplex.specs import EntrySpec
>>> EntrySpec('a.s', 0, (), FiniteEnumeratedSet(['S', 'I'])).read([1.0, 0.0]).tolist()
['I', 'S']
Source code in src/skcomplex/specs/_entry_spec.py
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
def read(self, values: npt.ArrayLike) -> npt.NDArray[np.generic]:
    """Return stored numbers as values of the domain: labels for a categorical domain, booleans for a boolean one.

    Args:
        values:
            The stored numbers.

    Returns:
        values:
            The values.

    Examples:
        >>> from sage.sets.finite_enumerated_set import FiniteEnumeratedSet
        >>> from skcomplex.specs import EntrySpec
        >>> EntrySpec('a.s', 0, (), FiniteEnumeratedSet(['S', 'I'])).read([1.0, 0.0]).tolist()
        ['I', 'S']
    """
    return EntrySpec._decode(self.domain, values)

view(vector)

Return the variable's components of a flat vector as a view with one row per member.

Parameters:

Name Type Description Default
vector NDArray[float64]

A flat vector.

required

Returns:

Name Type Description
view NDArray[float64]

A (rows, columns) view that writes through to the vector.

Source code in src/skcomplex/specs/_entry_spec.py
142
143
144
145
146
147
148
149
150
151
152
153
def view(self, vector: npt.NDArray[np.float64]) -> npt.NDArray[np.float64]:
    """Return the variable's components of a flat vector as a view with one row per member.

    Args:
        vector:
            A flat vector.

    Returns:
        view:
            A `(rows, columns)` view that writes through to the vector.
    """
    return vector[self.indices].reshape(self.rows, self.columns)

EventRecordSpec(label, time, before, after, member=None) dataclass

Bases: BaseRecordSpec

Event that happened during a run.

Parameters:

Name Type Description Default
label str

The name of the event.

required
time float

The time of the crossing.

required
before Array

The state vector at the crossing, before the reset.

required
after Array

The state vector after the reset.

required
member int | None

The member of the group whose event it is, or None for an event of single elements.

None

EvolutionStrategySpec(offspring=None) dataclass

Bases: BaseSpec

Settings of an evolution strategy.

Parameters:

Name Type Description Default
offspring int | None

The number of offspring per generation, or None for pymoo's default.

None

Examples:

>>> from skcomplex.specs import EvolutionStrategySpec
>>> EvolutionStrategySpec(offspring=200).check().offspring
200

ExtremalRecordSpec(label, time, site, value) dataclass

Bases: BaseRecordSpec

Application of an extremal law, such as the reset of the member with the smallest value.

Parameters:

Name Type Description Default
label str

The label of the extremal law.

required
time float

The time of the step.

required
site int

The member index of the extremal site, in row-major order on a lattice or node order on a network.

required
value float

The extremal value of the key state before the update.

required

FractionalRowsSpec(law, positions, hurst) dataclass

Bases: BaseSpec

Noise rows of one fractional noise law, driven by fractional Brownian motion of a Hurst index.

Parameters:

Name Type Description Default
law str

The description of the law, such as fractional noise law of walkers.x.

required
positions NDArray[intp]

The positions of the law's rows among the noise rows of the problem.

required
hurst Callable[[Array], Array]

The function H(p) that returns the Hurst index of every row from the parameter vector.

required

FractionalStateSpec(path, name, order) dataclass

Bases: BaseSpec

State of a fractional order with the path of its component.

Parameters:

Name Type Description Default
path str

The path of the element or group.

required
name str

The dotted name of the state.

required
order float

The order of the state.

required

HilbertSpec(dimension, operators=dict(), basis=dict(), display='z') dataclass

Bases: BaseSpec

Spec of the complex vector space of an element, with the local operators its laws build generators from.

An element that takes a HilbertSpec and declares a complex state, a StateSpec over CC or CC^dimension, is a subsystem. Its laws read every local operator by name, and a group of such elements is the tensor product of its members' spaces, in member order.

Parameters:

Name Type Description Default
dimension int

The dimension of the space.

required
operators Mapping[str, tuple[ArrayLike, bool]]

A mapping from operator name to its matrix and whether it is Hermitian, such as {'z': (matrix, True)}.

dict()
basis Mapping[str, int]

A mapping from the label of a basis state to its index, such as {'up': 0, 'down': 1}.

dict()
display str | None

The name of the operator whose expectation visuals show for a group of such elements, or None for the probabilities of the basis states.

'z'

Examples:

>>> import numpy as np
>>> from skcomplex.specs import HilbertSpec
>>> spec = HilbertSpec(2, {'z': (np.diag([1.0, -1.0]), True)}, basis={'up': 0, 'down': 1}).check()
>>> spec.basis['down']
1

HyperedgeReductionSpec(call, kind, argument, weight, size) dataclass

Bases: BaseSpec

Reduction over the hyperedges around every member found in an expression, with its kind, argument, and size.

Parameters:

Name Type Description Default
call Expression

The unevaluated call.

required
kind str

One of 'sum', 'mean', 'count', 'max', 'min', 'normalized-mean', and 'argmax'.

required
argument Expression

The value of one hyperedge.

required
weight Expression | None

The weight of one hyperedge, or None for 1.

required
size int | None

The number of members of the hyperedges reduced over, or None for every size.

required

IssueSpec(code, path, message, fix, severity=_ERROR, error=ValidationError) dataclass

Bases: BaseSpec

Problem that validation found in a system, with where it is and how to fix it.

Parameters:

Name Type Description Default
code str

The stable code of the problem, such as 'law-domain'.

required
path str

The slash path of the component or system the problem is in.

required
message str

What is wrong and why.

required
fix str

The change that makes the system valid.

required
severity str

'error' for problems that stop compilation, 'warning' otherwise.

_ERROR
error type[SkcomplexError]

The class of the error raised for the problem: ValidationError or one of its subclasses for the problems validation finds, and the class of the original error for a component that fails to declare.

ValidationError

text property

IssueSpec as one line with its path, code, message, and fix.

IterativeMatchingSpec(adjustment=0.1, iterations=500, tolerance=0.001) dataclass

Bases: BaseSpec

Iterative matching that adjusts a clearing value until the requested and provided quantities balance.

Starting from the last clearing value, or the median of the limits, the value moves by p <- p (1 + adjustment (D - S) / (D + S)) until the relative excess of requests falls below tolerance, where D is the quantity requested by requesters whose limit is at least p and S the quantity of providers whose limit is at most p. The members then match at that value, and the long side is rationed in random order (Hamill and Gilbert 2016 ch. 5).

Parameters:

Name Type Description Default
adjustment float

The speed of the value adjustment.

0.1
iterations int

The largest number of adjustments per clearing.

500
tolerance float

The relative excess of requests at which the adjustment stops.

0.001

Examples:

>>> from skcomplex.specs import IterativeMatchingSpec
>>> IterativeMatchingSpec(adjustment=0.05).check().iterations
500

JumpPathSpec(times, states, label) dataclass

Bases: BaseSpec

Path of a discrete state with the time of every jump.

Parameters:

Name Type Description Default
times Array

The first time, then the time of every frame at which the state changed.

required
states Array

The state at the first time and after every jump, one row per jump for vector states.

required
label str

The name of the state.

required

LayerSpec(label, graph) dataclass

Bases: BaseSpec

Spec of a relation over the nodes of a network space, such as contacts or employment, held as a graph of its own.

A network space holds several layers over the same nodes. Edge groups and interactions over neighbours name the layer they bind to, and reductions reduce over its edges with AdjacencyNeighborhood(layer=label).

Parameters:

Name Type Description Default
label str

The name of the layer, unique in its network space.

required
graph Graph

The NetworkX graph of the relation, over the nodes of the network space.

required

Examples:

>>> import networkx as nx
>>> from skcomplex.specs import LayerSpec
>>> LayerSpec('work', nx.path_graph(3)).check().label
'work'

LayoutSpec(entries) dataclass

Bases: BaseSpec

Ordered collection of named variables stored in one flat vector.

Parameters:

Name Type Description Default
entries tuple[EntrySpec, ...]

The entries, in vector order.

required

Examples:

>>> import numpy as np
>>> from skcomplex.specs import EntrySpec, LayoutSpec
>>> from sage.all__sagemath_symbolics import CC, RR
>>> layout = LayoutSpec((EntrySpec('a.n', 0, (), RR), EntrySpec('b.x', 1, (2,), RR)))
>>> layout.read(np.array([1.0, 2.0, 3.0]), 'b.x')
array([2., 3.])

component_names property

Names of the components, in vector order.

names property

Dotted names of the variables, in vector order.

size property

Number of components of the flat vector.

entry(name)

Return the entry of a variable.

Parameters:

Name Type Description Default
name str

The dotted name of the variable.

required

Returns:

Name Type Description
entry EntrySpec

The entry of the variable.

Raises:

Type Description
KeyError

The name is not part of the layout.

Source code in src/skcomplex/specs/_layout_spec.py
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
def entry(self, name: str) -> EntrySpec:
    """Return the entry of a variable.

    Args:
        name:
            The dotted name of the variable.

    Returns:
        entry:
            The entry of the variable.

    Raises:
        KeyError:
            The name is not part of the layout.
    """
    if name not in self._by_name:
        error_msg = f'No variable named {name!r}. Available names are: {", ".join(self.names)}.'
        raise KeyError(error_msg)
    return self._by_name[name]

has(name)

Check whether a variable name is part of the layout.

Parameters:

Name Type Description Default
name str

The dotted name of a variable.

required

Returns:

Name Type Description
found bool

Whether the layout has a variable of that name.

Source code in src/skcomplex/specs/_layout_spec.py
42
43
44
45
46
47
48
49
50
51
52
53
def has(self, name: str) -> bool:
    """Check whether a variable name is part of the layout.

    Args:
        name:
            The dotted name of a variable.

    Returns:
        found:
            Whether the layout has a variable of that name.
    """
    return name in self._by_name

locate(name)

Return the entry of a variable or of one of its components, and the slice of the vector it covers.

Parameters:

Name Type Description Default
name str

The dotted name of a variable, or of one component such as regulation.weights[1].

required

Returns:

Name Type Description
location tuple[EntrySpec, slice]

The entry of the variable, a scalar entry for a component, and the slice of its values.

Raises:

Type Description
KeyError

The name is neither a variable nor a component of the layout.

Examples:

>>> from skcomplex.specs import EntrySpec, LayoutSpec
>>> from sage.all__sagemath_symbolics import CC, RR
>>> layout = LayoutSpec((EntrySpec('a.n', 0, (), RR), EntrySpec('b.w', 1, (3,), RR)))
>>> entry, indices = layout.locate('b.w[1]')
>>> entry.name, entry.shape, indices
('b.w[1]', (), slice(2, 3, None))
Source code in src/skcomplex/specs/_layout_spec.py
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
def locate(self, name: str) -> tuple[EntrySpec, slice]:
    """Return the entry of a variable or of one of its components, and the slice of the vector it covers.

    Args:
        name:
            The dotted name of a variable, or of one component such as `regulation.weights[1]`.

    Returns:
        location:
            The entry of the variable, a scalar entry for a component, and the slice of its values.

    Raises:
        KeyError:
            The name is neither a variable nor a component of the layout.

    Examples:
        >>> from skcomplex.specs import EntrySpec, LayoutSpec
        >>> from sage.all__sagemath_symbolics import CC, RR
        >>> layout = LayoutSpec((EntrySpec('a.n', 0, (), RR), EntrySpec('b.w', 1, (3,), RR)))
        >>> entry, indices = layout.locate('b.w[1]')
        >>> entry.name, entry.shape, indices
        ('b.w[1]', (), slice(2, 3, None))
    """
    if name in self._by_name:
        entry = self._by_name[name]
        return entry, entry.indices
    found = self._by_name.get(name.partition('[')[0].removesuffix('.real').removesuffix('.imag'))
    if found is not None and name in found.component_names:
        start = found.start + found.component_names.index(name)
        return EntrySpec(name, start, (), RR if found.is_complex else found.domain), slice(
            start,
            start + 1,
        )
    error_msg = f'No variable or component named {name!r}. Available names are: {", ".join(self.names)}.'
    raise KeyError(error_msg)

read(vector, name)

Return the value of a variable from a flat vector or from rows of flat vectors.

Parameters:

Name Type Description Default
vector NDArray[float64]

A flat vector, or a 2D array with one flat vector per row.

required
name str

The dotted name of the variable.

required

Returns:

Name Type Description
value Array | ComplexArray | float | complex

A number for a scalar in a flat vector, or an array whose shape is the leading shape of vector followed by the shape of the variable, complex for a complex variable.

Source code in src/skcomplex/specs/_layout_spec.py
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
def read(self, vector: npt.NDArray[np.float64], name: str) -> Array | ComplexArray | float | complex:
    """Return the value of a variable from a flat vector or from rows of flat vectors.

    Args:
        vector:
            A flat vector, or a 2D array with one flat vector per row.

        name:
            The dotted name of the variable.

    Returns:
        value:
            A number for a scalar in a flat vector, or an array whose shape is the leading shape of `vector`
            followed by the shape of the variable, complex for a complex variable.
    """
    entry = self.entry(name)
    values = entry.decode(vector[..., entry.indices]).reshape(vector.shape[:-1] + entry.shape)
    if values.ndim:
        return values
    return complex(values) if entry.is_complex else float(values)

values(vector)

Return the value of every variable of a flat vector.

Parameters:

Name Type Description Default
vector NDArray[float64]

A flat vector.

required

Returns:

Name Type Description
values dict[str, Array | ComplexArray | float | complex]

A mapping from dotted name to value.

Source code in src/skcomplex/specs/_layout_spec.py
147
148
149
150
151
152
153
154
155
156
157
158
def values(self, vector: npt.NDArray[np.float64]) -> dict[str, Array | ComplexArray | float | complex]:
    """Return the value of every variable of a flat vector.

    Args:
        vector:
            A flat vector.

    Returns:
        values:
            A mapping from dotted name to value.
    """
    return {name: self.read(vector, name) for name in self._by_name}

LocalOperatorSpec(name, matrix=None, hermitian=False) dataclass

Bases: BaseSpec

Operator that acts on the Hilbert space of one subsystem, identified by its name.

Parameters:

Name Type Description Default
name str

The name of the operator, unique among the operators of its subsystem.

required
matrix object

The matrix of the operator.

None
hermitian bool

Whether the operator equals its adjoint.

False

Examples:

>>> import qutip
>>> from skcomplex.specs import LocalOperatorSpec
>>> LocalOperatorSpec('plus', qutip.sigmap()).adjoint().name
'minus'

adjoint()

Return the adjoint of the operator.

Returns:

Name Type Description
adjoint LocalOperatorSpec

The operator itself when it is Hermitian, or the operator with the conjugate transposed matrix.

Source code in src/skcomplex/specs/_local_operator_spec.py
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
def adjoint(self) -> 'LocalOperatorSpec':
    """Return the adjoint of the operator.

    Returns:
        adjoint:
            The operator itself when it is Hermitian, or the operator with the conjugate transposed matrix.
    """
    if self.hermitian:
        return self
    if self.name in _ADJOINT_NAMES:
        name = _ADJOINT_NAMES[self.name]
    elif self.name.endswith(_ADJOINT_SUFFIX):
        name = self.name.removesuffix(_ADJOINT_SUFFIX)
    else:
        name = f'{self.name}{_ADJOINT_SUFFIX}'
    matrix = self._sparse_matrix(self.matrix).conj().T.tocsr()
    return LocalOperatorSpec(name, matrix, hermitian=False)

LookupSpec(kind, base, values, columns=1) dataclass

Bases: BaseSpec

Lookup array of a table or totalistic rule.

Parameters:

Name Type Description Default
kind str

'table', 'totalistic', or 'outer'.

required
base int

The number of state values.

required
values Array

The next value by pattern code, by sum, or by cell value and sum in row-major order.

required
columns int

The number of sums of an outer totalistic rule.

1

LoweredFunctionsSpec(drift=None, diffusion=None, noise_rows=(lambda: np.zeros(0, dtype=np.intp))(), noise_columns=(lambda: np.zeros(0, dtype=np.intp))(), n_processes=0, noise_blocks=(), propensities=None, jumps=(), update=None, boundary=None, accelerated=None, backends=dict()) dataclass

Bases: BaseSpec

Numeric functions of a form produced by a backend.

Parameters:

Name Type Description Default
drift VectorFunction | None

The drift function, or None.

None
diffusion VectorFunction | None

The function that returns every Wiener process amplitude, or None.

None
noise_rows Indices

The state index each noise amplitude drives.

(lambda: zeros(0, dtype=intp))()
noise_columns Indices

The Wiener process each noise amplitude draws.

(lambda: zeros(0, dtype=intp))()
n_processes int

The number of Wiener processes.

0
noise_blocks tuple[WienerBlockSpec, ...]

The blocks of correlated processes with their covariance factors.

()
propensities VectorFunction | None

The function that returns every jump channel rate, or None.

None
jumps tuple[_JumpChannelsSpec, ...]

The channels of every jump law.

()
update VectorFunction | None

The next-state function of a discrete map, or None.

None
boundary VectorFunction | None

The function that applies the boundary laws, or None.

None
accelerated AcceleratedSpec | None

The compiled stepper loops, or None when the backend has none.

None
backends Mapping[str, str]

The backend that runs the kernels of every law kind, by the kind's name, when it differs by kind.

dict()

MatchSpec(requester, provider, quantity, value) dataclass

Bases: BaseSpec

Match of a requester with a provider, of a quantity at a clearing value per unit.

Parameters:

Name Type Description Default
requester object

The agent view of the requester.

required
provider object

The agent view of the provider.

required
quantity float

The matched quantity.

required
value float

The clearing value per unit.

required

Examples:

>>> from skcomplex.specs import MatchSpec
>>> MatchSpec('a', 'b', 2.0, 5.0).check().quantity
2.0

MatrixLawSpec(owner, description, matrix) dataclass

Bases: BaseSpec

Matrix of a Markov law of a component, with the description of the law.

Parameters:

Name Type Description Default
owner str

The path of the component.

required
description str

The description of the law.

required
matrix Sequence[Sequence[object]]

The rows of the matrix.

required

MoveSpec(target, kind='flip', values=(), width=0.0, function=None) dataclass

Bases: BaseSpec

Spec of the proposed change of the value of a lattice site in a Monte Carlo sweep.

Parameters:

Name Type Description Default
target object

The symbol of the lattice state the move changes.

required
kind str

'flip' for the negative value, the spin flip of Ising models, 'random-value' for a value drawn from values, as in Potts models, 'rotate' for the value plus a uniform number in [-width, width], as in XY models, 'gaussian' for the value plus a normal number of standard deviation width, 'function' for the values function proposes, or 'cluster' for the flip of a cluster grown by the Wolff bonds of the energy.

'flip'
values tuple[float, ...]

The values a random-value move draws from.

()
width float

The largest change of a rotation, or the standard deviation of a Gaussian move.

0.0
function Callable[..., object] | None

The function function(values, random) of the array of the current values of some sites and the random generator that returns their proposed values, for the kind 'function'.

None

Raises:

Type Description
ValidationError

The kind of move is unknown, or a function move has no callable function.

Examples:

>>> from sage.all__sagemath_symbolics import var
>>> from skcomplex.specs import MoveSpec
>>> MoveSpec(var('color'), 'random-value', values=(0.0, 1.0, 2.0)).check().values
(0.0, 1.0, 2.0)

NeighborReadSpec(table, ghost, sizes, steps, mode, entry=None, order=None) dataclass

Bases: BaseSpec

How a symbol reads a field at a neighbouring site of every member.

Parameters:

Name Type Description Default
table Indices

The member index of the neighbour of every member, with the number of members for the fixed value.

required
ghost float | None

The value read outside fixed edges, or None when no neighbour is outside.

required
sizes tuple[int, ...] | None

The lattice shape, or None on a network.

required
steps IntTuple | None

The offset of the neighbour on a lattice, or None on a network.

required
mode int

0 for periodic, 1 for zero-flux, and 2 for fixed edges.

required
entry EntrySpec | None

The parameter entry whose flat values at the table hold the member of every row, for members that change during a run, such as those of a growing hypergraph, or None when the table holds the members.

None
order Indices | None

The member at every position of an order drawn again at every step, whose positions the table holds, or None for a table of members.

None

members(p)

Return the member every row reads, from the table or the parameter entry at the table, through the order.

Parameters:

Name Type Description Default
p Array

The parameter vector.

required

Returns:

Name Type Description
members Indices

The member index of every row.

Source code in src/skcomplex/specs/_neighbor_read_spec.py
53
54
55
56
57
58
59
60
61
62
63
64
65
def members(self, p: Array) -> Indices:
    """Return the member every row reads, from the table or the parameter entry at the table, through the order.

    Args:
        p:
            The parameter vector.

    Returns:
        members:
            The member index of every row.
    """
    rows = self.table if self.entry is None else self.entry.view(p).ravel()[self.table].astype(np.intp)
    return rows if self.order is None else self.order[rows]

read(column, p)

Return the neighbour's value of every member from the column of values.

Parameters:

Name Type Description Default
column NDArray[float64]

One value per member.

required
p Array

The parameter vector, which holds the members of a table that changes during a run.

required

Returns:

Name Type Description
values NDArray[float64]

The value at the neighbour of every member.

Source code in src/skcomplex/specs/_neighbor_read_spec.py
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
def read(self, column: npt.NDArray[np.float64], p: Array) -> npt.NDArray[np.float64]:
    """Return the neighbour's value of every member from the column of values.

    Args:
        column:
            One value per member.

        p:
            The parameter vector, which holds the members of a table that changes during a run.

    Returns:
        values:
            The value at the neighbour of every member.
    """
    if self.ghost is None:
        return column[self.members(p)]
    return np.append(column, self.ghost)[self.table]

NeighborReductionSpec(call, kind, argument, weight, over) dataclass

Bases: BaseSpec

Neighbourhood reduction found in an expression, with its kind, argument, weight, and neighbourhood.

Parameters:

Name Type Description Default
call Expression

The unevaluated call.

required
kind str

One of 'sum', 'mean', 'count', 'max', 'min', 'normalized-mean', 'argmax', and the components reductions 'component-label', 'component-size', 'component-largest', and 'component-giant'.

required
argument Expression

The value of one neighbour.

required
weight Expression | None

The weight of one neighbour, or None for 1.

required
over object

The neighbourhood, or None for the neighbours of the space.

required

NetworkRowsSpec(nodes, edges, directed, hyperedges=None) dataclass

Bases: BaseSpec

Variable groups of one network: the groups on its nodes, the edge group of every changing layer, and hyperedges.

Parameters:

Name Type Description Default
nodes tuple[CapacityRowsSpec, ...]

The groups on the nodes, which share their rows.

required
edges Mapping[str | None, CapacityRowsSpec]

The variable edge group of every layer by label, None for the graph of the network.

required
directed Mapping[str | None, bool]

Whether the edges of every layer are directed.

required
hyperedges CapacityRowsSpec | None

The variable group on the hyperedges of the network, or None for hyperedges that do not change.

None

neighbours(layer, node, p)

Return the node rows a node joins in a layer, its successors on a directed layer.

Parameters:

Name Type Description Default
layer str | None

The layer.

required
node int

The node row.

required
p Array

The parameter vector.

required

Returns:

Name Type Description
neighbours Indices

The node rows.

Source code in src/skcomplex/specs/_network_rows_spec.py
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
def neighbours(self, layer: str | None, node: int, p: Array) -> Indices:
    """Return the node rows a node joins in a layer, its successors on a directed layer.

    Args:
        layer:
            The layer.

        node:
            The node row.

        p:
            The parameter vector.

    Returns:
        neighbours:
            The node rows.
    """
    edges = self.edges[layer]
    sources, targets = edges.ends(p)
    present = edges.present(p)
    found = targets[present & (sources == node)]
    if self.directed[layer]:
        return found
    return np.concatenate([found, sources[present & (targets == node)]])

order_ends(layer, first, second)

Return the ends of an edge, in node order on an undirected layer.

Parameters:

Name Type Description Default
layer str | None

The layer.

required
first int

The node row of one end.

required
second int

The node row of the other end.

required

Returns:

Name Type Description
ends Pair

The source and target node rows.

Source code in src/skcomplex/specs/_network_rows_spec.py
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
def order_ends(self, layer: str | None, first: int, second: int) -> Pair:
    """Return the ends of an edge, in node order on an undirected layer.

    Args:
        layer:
            The layer.

        first:
            The node row of one end.

        second:
            The node row of the other end.

    Returns:
        ends:
            The source and target node rows.
    """
    return (first, second) if self.directed[layer] else (min(first, second), max(first, second))

present(p)

Return whether every node row holds a node.

Parameters:

Name Type Description Default
p Array

The parameter vector.

required

Returns:

Name Type Description
present NDArray[bool_]

One flag per node row.

Source code in src/skcomplex/specs/_network_rows_spec.py
41
42
43
44
45
46
47
48
49
50
51
52
def present(self, p: Array) -> npt.NDArray[np.bool_]:
    """Return whether every node row holds a node.

    Args:
        p:
            The parameter vector.

    Returns:
        present:
            One flag per node row.
    """
    return self.nodes[0].present(p)

snapshot(p, layer)

Return the nodes and the edges of a layer present at the parameters of a frame.

Parameters:

Name Type Description Default
p Array

The parameter vector of the frame.

required
layer str | None

The layer.

required

Returns:

Name Type Description
snapshot NetworkSnapshotSpec

The nodes and edges present.

Source code in src/skcomplex/specs/_network_rows_spec.py
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
def snapshot(self, p: Array, layer: str | None) -> NetworkSnapshotSpec:
    """Return the nodes and the edges of a layer present at the parameters of a frame.

    Args:
        p:
            The parameter vector of the frame.

        layer:
            The layer.

    Returns:
        snapshot:
            The nodes and edges present.
    """
    edges = self.edges[layer]
    present = edges.present(p)
    sources, targets = edges.ends(p)
    hyperedges = None
    if self.hyperedges is not None:
        hyperedges = self.hyperedges.hyperedges(p)[self.hyperedges.present(p)]
    return NetworkSnapshotSpec(
        np.flatnonzero(self.present(p)).astype(np.intp),
        sources[present],
        targets[present],
        np.flatnonzero(present).astype(np.intp),
        hyperedges,
    )

NetworkSnapshotSpec(nodes, sources, targets, edges, hyperedges=None) dataclass

Bases: BaseSpec

Nodes, edges, and hyperedges of a network layer at one frame.

Parameters:

Name Type Description Default
nodes NDArray[intp]

The rows of the nodes present, in increasing order.

required
sources NDArray[intp]

The node row of the source of every edge present.

required
targets NDArray[intp]

The node row of the target of every edge present.

required
edges NDArray[intp]

The row of every edge present in its edge group.

required
hyperedges NDArray[intp] | None

The member nodes of every hyperedge present, one row per hyperedge, or None for a network whose hyperedges do not change.

None

graph()

Return the NetworkX graph of the snapshot, whose nodes are the node rows present.

Returns:

Name Type Description
graph Graph

The undirected graph of the nodes and edges present.

Examples:

>>> import numpy as np
>>> from skcomplex.specs import NetworkSnapshotSpec
>>> rows = np.array([0, 1, 2])
>>> snapshot = NetworkSnapshotSpec(rows, np.array([0, 1]), np.array([1, 2]), np.array([0, 1]))
>>> sorted(snapshot.graph().edges())
[(0, 1), (1, 2)]
Source code in src/skcomplex/specs/_network_snapshot_spec.py
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
def graph(self) -> nx.Graph:
    """Return the NetworkX graph of the snapshot, whose nodes are the node rows present.

    Returns:
        graph:
            The undirected graph of the nodes and edges present.

    Examples:
        >>> import numpy as np
        >>> from skcomplex.specs import NetworkSnapshotSpec
        >>> rows = np.array([0, 1, 2])
        >>> snapshot = NetworkSnapshotSpec(rows, np.array([0, 1]), np.array([1, 2]), np.array([0, 1]))
        >>> sorted(snapshot.graph().edges())
        [(0, 1), (1, 2)]
    """
    graph = nx.Graph()
    graph.add_nodes_from(self.nodes.tolist())
    graph.add_edges_from(zip(self.sources.tolist(), self.targets.tolist(), strict=True))
    return graph

NoiseProcessSpec(key, index=0, dimension=0, factor=None, links=None) dataclass

Bases: BaseSpec

Named Wiener process that a noise output draws, shared by every output with the same key.

Parameters:

Name Type Description Default
key object

The identity of the process: a local label of a component, or the path of a WienerProcessSpec.

required
index int

The process within a WienerProcessSpec.

0
dimension int

The number of processes of a WienerProcessSpec, or 0 for a local label, which takes one process per member.

0
factor NDArray[float64] | None

The factor L with L L^T = C of the covariance of a WienerProcessSpec, or None for the identity.

None
links NDArray[intp] | None

For the link processes of a conserved noise, the process of every evaluation index among the dimension processes of the key, or -1 for a link that carries no process, otherwise None.

None

ObjectiveSpec(expression, over) dataclass

Bases: BaseSpec

Spec of the local objective of a lattice site, every term of the total objective that involves the site's value.

The change of a move is the difference of the local objective at the proposed and the current value. Neighbour values are read with neighbors(..., reduce='each') in neighbourhood order, or summed with neighbors(..., reduce='sum').

Parameters:

Name Type Description Default
expression object

The local objective, a symbolic expression of the states of the site, its neighbours, and parameters.

required
over object

The neighbourhood that neighbors reads in the expression.

required

Examples:

>>> from sage.all__sagemath_symbolics import var
>>> from skcomplex.core.spaces import VonNeumannNeighborhood
>>> from skcomplex.specs import ObjectiveSpec
>>> spin, J = var('spin J')
>>> ObjectiveSpec(-J * spin, VonNeumannNeighborhood()).check().expression
-J*spin

ObservableSpec(label, expression=None, element=None, group=None, reduce='mean', variable=None, function=None) dataclass

Bases: BaseSpec

Spec of a named value of a system that a run computes from its states and parameters at every frame.

An observable is an expression of the namespace of the system, of one element when element is given, or a reduction over the members of a group of an expression or a variable of each member. A run records it in its trajectory under <system path>/<label>, or <element>.<label> for an element, and laws of other partitions read it through a role bound to its path.

Parameters:

Name Type Description Default
label str

The label of the observable, unique among the observables of its system.

required
expression object

A function of the namespace of the system, of the element, or of one member, or a symbolic expression.

None
element str | None

The label of an element or an interaction of the root system whose namespace the expression reads, or None.

None
group str | None

The path of the group to reduce over, relative to the system, or None for no reduction.

None
reduce str | Callable[[AnyArray], object]

'count', 'sum', 'mean', 'min', 'max', 'var', 'logsumexp', or a function of the array of member values.

'mean'
variable str | None

The name of the member variable to reduce, instead of an expression.

None
function Callable[[float, Mapping[str, object]], object] | None

A function f(t, values) of time and the mapping from the dotted name of every state and parameter to its value, instead of an expression, for a system without agents. A module-level function, since observables are pickled.

None

Examples:

>>> from skcomplex.specs import ObservableSpec
>>> ObservableSpec('mean_wealth', group='traders', variable='wealth').check().reduce
'mean'

OperatorSpec(terms) dataclass

Bases: BaseSpec

Sum of products of local operators of subsystems, each product with a symbolic coefficient.

The compiler lowers the Sage operator expressions of laws and observables to operators with operator_of. Operators combine by sums, products, scalar multiplication, and adjoint. A coefficient is a number or a Sage expression of parameters and time. A number added to an operator stands for that multiple of the identity.

Parameters:

Name Type Description Default
terms Mapping[Product, object]

A mapping from a tuple of factors, each the key of a subsystem and a local operator, in product order, to the coefficient of the product. The empty tuple is the identity.

required

Examples:

>>> import qutip
>>> from sage.all__sagemath_symbolics import var
>>> from skcomplex.specs import LocalOperatorSpec, OperatorSpec
>>> x = LocalOperatorSpec('x', qutip.sigmax(), hermitian=True)
>>> a, b = OperatorSpec({(('a', x),): 1}), OperatorSpec({(('b', x),): 1})
>>> (var('J') * a * b).text
'J*a.x*b.x'

subsystems property

Keys of the subsystems every term acts on, in term order.

text property

OperatorSpec in operator notation, a sum of coefficients times products of local operators.

__add__(other)

Return the sum of the operator and an operator or a multiple of the identity.

Source code in src/skcomplex/specs/_operator_spec.py
64
65
66
67
68
69
70
71
72
def __add__(self, other: object) -> 'OperatorSpec':
    """Return the sum of the operator and an operator or a multiple of the identity."""
    operand = self._as_operator(other)
    if operand is None:
        return NotImplemented
    terms = self._items()
    for key, value in operand._items().items():
        self._added(terms, key, value)
    return self._combined(terms)

__mul__(other)

Return the product of the operator and an operator or a scalar, in this order.

Source code in src/skcomplex/specs/_operator_spec.py
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
def __mul__(self, other: object) -> 'OperatorSpec':
    """Return the product of the operator and an operator or a scalar, in this order."""
    operand = self._as_operator(other)
    if operand is None:
        return NotImplemented
    terms: dict[Product, Expression] = {}
    for left, first in self._items().items():
        for right, second in operand._items().items():
            self._added(terms, left + right, first * second)
    return self._combined(terms)

__neg__()

Return the operator with every coefficient negated.

Source code in src/skcomplex/specs/_operator_spec.py
78
79
80
def __neg__(self) -> 'OperatorSpec':
    """Return the operator with every coefficient negated."""
    return OperatorSpec({key: -value for key, value in self._items().items()})

__radd__(other)

Return the sum of a multiple of the identity and the operator.

Source code in src/skcomplex/specs/_operator_spec.py
74
75
76
def __radd__(self, other: object) -> 'OperatorSpec':
    """Return the sum of a multiple of the identity and the operator."""
    return self.__add__(other)

__rmul__(other)

Return the product of a scalar and the operator.

Source code in src/skcomplex/specs/_operator_spec.py
102
103
104
105
def __rmul__(self, other: object) -> 'OperatorSpec':
    """Return the product of a scalar and the operator."""
    operand = self._as_operator(other)
    return NotImplemented if operand is None else operand * self

__rsub__(other)

Return the difference of a multiple of the identity and the operator.

Source code in src/skcomplex/specs/_operator_spec.py
87
88
89
def __rsub__(self, other: object) -> 'OperatorSpec':
    """Return the difference of a multiple of the identity and the operator."""
    return (-self) + other

__sub__(other)

Return the difference of the operator and an operator or a multiple of the identity.

Source code in src/skcomplex/specs/_operator_spec.py
82
83
84
85
def __sub__(self, other: object) -> 'OperatorSpec':
    """Return the difference of the operator and an operator or a multiple of the identity."""
    operand = self._as_operator(other)
    return NotImplemented if operand is None else self + (-operand)

__truediv__(other)

Return the operator divided by a scalar.

Source code in src/skcomplex/specs/_operator_spec.py
107
108
109
110
def __truediv__(self, other: object) -> 'OperatorSpec':
    """Return the operator divided by a scalar."""
    coefficient = self._coefficient(other)
    return NotImplemented if coefficient is None else self * (1 / coefficient)

adjoint()

Return the adjoint operator, with conjugate coefficients and reversed products of adjoint factors.

Returns:

Name Type Description
adjoint OperatorSpec

The adjoint operator.

Examples:

>>> import qutip
>>> from skcomplex.specs import LocalOperatorSpec, OperatorSpec
>>> plus = LocalOperatorSpec('plus', qutip.sigmap())
>>> (2j * OperatorSpec({(('q', plus),): 1})).adjoint().text
'(-2j)*q.minus'
Source code in src/skcomplex/specs/_operator_spec.py
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
def adjoint(self) -> 'OperatorSpec':
    """Return the adjoint operator, with conjugate coefficients and reversed products of adjoint factors.

    Returns:
        adjoint:
            The adjoint operator.

    Examples:
        >>> import qutip
        >>> from skcomplex.specs import LocalOperatorSpec, OperatorSpec
        >>> plus = LocalOperatorSpec('plus', qutip.sigmap())
        >>> (2j * OperatorSpec({(('q', plus),): 1})).adjoint().text
        '(-2j)*q.minus'
    """
    return OperatorSpec(
        {
            tuple((subsystem, local.adjoint()) for subsystem, local in reversed(key)): value.conjugate()
            for key, value in self._items().items()
        },
    )

OuterTotalisticSpec(rule, default=0.0, states=2) dataclass

Bases: BaseSpec

Rule given by the next value of every pair of the cell's value and the sum of its neighbours' values.

Parameters:

Name Type Description Default
rule Mapping[tuple[int, int], float] | Callable[[IntArray, IntArray], ArrayLike]

A mapping from (value, sum) to next value, or a function of the values and the sums.

required
default float

The next value of pairs a mapping leaves out.

0.0
states int

The number of state values 0 to states - 1, which bounds the sums.

2

Examples:

>>> from skcomplex.specs import OuterTotalisticSpec
>>> parity = OuterTotalisticSpec(lambda center, total: (center + total) % 2)
>>> parity.states
2

PairReadSpec(read, side, image=False, table=None) dataclass

Bases: BaseSpec

How a neighbourhood reduction reads one symbol for every pair of a member and a neighbour.

Parameters:

Name Type Description Default
read ReadSpec

The values of the symbol, one per member or one shared value.

required
side str

'shared' for one value, 'reader' for the value of the member that reads the reduction, 'other' for the value of the neighbour, 'edge' for the value of the member of a group on the edges of a network layer that joins them, or 'pair' for the value of the pair itself, the entry of a shaped parameter at the position of the pair among the pairs of every member and every other member.

required
image bool

Whether the symbol is a position component of the neighbour, read by its minimum image from the reader.

False
table Indices | None

The member that every neighbour stands for, for an 'other' read whose neighbours are rows of a table, such as one other member of the hyperedges around the reader, or None for the neighbour itself.

None

ParameterSpec(domain=RR, vector=False, per=None, adaptive=False, bounds=None, shape=None) dataclass

Bases: BaseSpec

Spec of a parameter of an element or an interaction, in the annotation of an argument of its constructor.

The default of the argument is the default of the parameter. A parameter per entry of a variadic role holds one value per entry of the role, and an adaptive parameter is a state that laws may change, such as a policy rate.

Parameters:

Name Type Description Default
domain object

The Sage set of the values of the parameter, such as RR or RealSet.open(0, oo).

RR
vector bool

Whether the parameter has one component per dimension of the enclosing space.

False
per str | None

The name of a variadic role whose entries the parameter holds one value for, or None.

None
adaptive bool

Whether laws may change the parameter.

False
bounds tuple[float, float] | None

The lower and upper bound of an adaptive parameter that is a control input, or None for none.

None
shape tuple[str, ...] | None

The names of the roles whose group sizes give the shape of the parameter, such as ('target', 'source') for a matrix with one row per member of the target and one column per member of the source, or None for a scalar. A role repeated k times gives a tensor of order k.

None

Examples:

>>> from sage.all__sagemath_symbolics import oo
>>> from sage.sets.real_set import RealSet
>>> from skcomplex.specs import ParameterSpec
>>> 0.5 in ParameterSpec(domain=RealSet.open(0, oo)).check().domain
True

ParametersSpec(symbols, time) dataclass

Bases: BaseSpec

Parameter symbols of the rewritten elements, in the order of the parameter vector.

Parameters:

Name Type Description Default
symbols tuple[Expression, ...]

The symbols.

required
time Expression

The generation symbol.

required

ParticleSwarmSpec(inertia=0.9, cognitive=2.0, social=2.0) dataclass

Bases: BaseSpec

Settings of particle swarm optimisation.

Parameters:

Name Type Description Default
inertia float

The weight of the previous velocity.

0.9
cognitive float

The attraction to the best position of a particle.

2.0
social float

The attraction to the best position of the swarm.

2.0

Examples:

>>> from skcomplex.specs import ParticleSwarmSpec
>>> ParticleSwarmSpec().check().inertia
0.9

PartnerSpec(candidates='all', choice='uniform', fallback=None, capacity=None, score=None, clearing='midpoint') dataclass

Bases: BaseSpec

Selection of partners: the candidates of every agent, a choice among them, a fallback, and a capacity.

Every agent of one side considers its candidates among the agents of the other side and picks among those that still have room. With a capacity the agents act in random order, since the first to act take the room. Without one they act in their order. A capacity of 1 with every agent as a candidate and a uniform choice draws disjoint random pairs from one random order per side.

Parameters:

Name Type Description Default
candidates str | float

The agents an agent considers, 'all', 'neighbors' for those in the cells or nodes around it, 'cell' for those in its cell or node, 'local' for both, a distance, or the name of a state of the agent that holds the distance.

'all'
choice str

How an agent picks among its candidates, 'uniform', 'score' for the largest score with ties broken at random, 'nearest', or 'all' for every candidate.

'uniform'
fallback str | None

The partner of an agent without candidates, 'nearest' for the nearest agent with room, or None for no partner.

None
capacity str | float | None

The largest number of pairs of an agent in one step, a number, the name of a state of the agent that holds it, or None for no limit.

None
score Preference | None

The function score(agent, candidate) of their agent views the choice 'score' reads, higher for preferred candidates, or None.

None
clearing str

The value of a pair that a matching settles, 'midpoint' of both limits, 'provider', or 'requester'.

'midpoint'

Raises:

Type Description
ValidationError

The choice, the fallback, or the clearing is unknown, the distance or the capacity is not positive, or the score does not fit the choice, raised by check.

Examples:

>>> from skcomplex.specs import PartnerSpec
>>> PartnerSpec(candidates='reach', fallback='nearest').check().candidates
'reach'

PartnerSwitchSpec(sample=3, intensity=1.0, partner='partner') dataclass

Bases: BaseSpec

Partner choice that samples providers and switches to one of a lower limit with some probability.

The rule follows chapter 2 of Caiani et al. (2016). Every requester, in random order, samples sample providers that still offer something. When the lowest limit among them is below the limit of its current partner, the requester switches with probability 1 - exp(intensity * (p_new - p_old) / p_new), and otherwise stays. It matches with its partner at the partner's limit, and the requester's state partner, when it has one, holds the id of the partner across steps.

Parameters:

Name Type Description Default
sample int

The number of providers every requester samples.

3
intensity float

The intensity of switching.

1.0
partner str

The name of the requester state that holds the id of its partner.

'partner'

Examples:

>>> from skcomplex.specs import PartnerSwitchSpec
>>> PartnerSwitchSpec(sample=2, intensity=4.0).check().intensity
4.0

PhaseSpec(name, activation='random', repeat=1, groups=None, visits=1.0, period=1, offset=0) dataclass

Bases: BaseSpec

Named part of a step, in which agents run the rules of the phase under an activation policy.

The policies are 'random', every agent in a new random order, 'sequential', every agent in the order of creation, 'simultaneous', every agent in random order reading the states of the start of the phase while its writes apply at the end of the phase, 'by-type', group after group in the order of groups or of declaration, each group in random order, and 'visits', as many visits as visits times the number of agents of groups at the start of the phase, each to an agent drawn at random with replacement, which runs its rules of the phase at the time k + i / n of visit i of n in step k. The rules of interactions and institutions in the phase run once after the agents. A phase with repeat above one runs that many rounds, such as intraday rounds within a day. A phase runs in the steps k, counted from one, for which k - offset is a multiple of period, so the default period of one runs it every step and a period of seven runs it once a week.

Parameters:

Name Type Description Default
name str

The name of the phase, which rules name in RuleLaw(function, phase=name).

required
activation str

The activation policy.

'random'
repeat int

The number of rounds of the phase per step.

1
groups Sequence[str] | None

The paths of the agent groups in their order of activation for 'by-type', or the groups whose agents 'visits' draws, or None for every group in the order of declaration.

None
visits float

The number of visits of 'visits' per agent of the groups at the start of the phase.

1.0
period int

The number of steps between two runs of the phase.

1
offset int

The step, modulo the period, in which the phase runs.

0

Examples:

>>> from skcomplex.specs import PhaseSpec
>>> PhaseSpec('trade', activation='simultaneous', repeat=3)
PhaseSpec(name='trade', activation='simultaneous', repeat=3, groups=None, visits=1.0, period=1, offset=0)

PhasesScheduleSpec(phases) dataclass

Bases: ScheduleSpec

Spec of a schedule of discrete time that runs named phases in order in every step.

Parameters:

Name Type Description Default
phases Sequence[PhaseSpec]

The phases, each with its rules and activation policy.

required

Examples:

>>> from skcomplex.specs import PhaseSpec, PhasesScheduleSpec
>>> [phase.name for phase in PhasesScheduleSpec((PhaseSpec('produce'), PhaseSpec('trade'))).check().phases]
['produce', 'trade']

QueueSpec(order='random') dataclass

Bases: BaseSpec

Queue of requesters served by the lowest providers until the quantities run out, so the last are rationed.

Requesters queue in random order, by decreasing limit, or in order of creation, and each matches at the limit of the lowest providers whose limit it accepts.

Parameters:

Name Type Description Default
order str

The order of the queue, 'random', 'limit', or 'sequential'.

'random'

Raises:

Type Description
ValidationError

The order is unknown, raised by check.

Examples:

>>> from skcomplex.specs import QueueSpec
>>> QueueSpec(order='limit').check().order
'limit'

RadiusSpec(radius, function, reduce='sum', priority=0) dataclass

Bases: BaseSpec

Term of the other agents within a radius of an agent, reduced by a sum or a mean, with a priority.

Every other agent within radius gives the vector function(agent, other, model), and the terms reduce by reduce. Among several radii, only the radii of the highest priority that hold another agent count.

Parameters:

Name Type Description Default
radius float | str

The radius, a number or the name of a parameter of the agent.

required
function Callable[..., object]

The term of one other agent, a function of the agent, the other agent, and the model view that returns a vector.

required
reduce str

'sum' or 'mean'.

'sum'
priority int

The priority of the radius, higher first.

0

Raises:

Type Description
ValidationError

The reduction is unknown, the function is not callable, or the radius is negative, raised by check.

Examples:

>>> from skcomplex.specs import RadiusSpec
>>> RadiusSpec(2.0, lambda agent, other, model: (1.0, 0.0), reduce='mean').check().reduce
'mean'

RandomSearchSpec(tries=1, clearing='midpoint') dataclass

Bases: BaseSpec

Random search: requesters in random order meet random providers and match when their limits cross.

Every requester makes up to tries meetings with providers that still offer something, and matches at the midpoint of the two limits, or at the requester's or the provider's limit, the decentralised exchange of Hamill and Gilbert (2016 ch. 5).

Parameters:

Name Type Description Default
tries int

The number of providers every requester meets.

1
clearing str

The value of a match, 'midpoint', 'requester', or 'provider'.

'midpoint'

Raises:

Type Description
ValidationError

The clearing rule is unknown, raised by check.

Examples:

>>> from skcomplex.specs import RandomSearchSpec
>>> RandomSearchSpec(tries=3).check().tries
3

ReadSpec(is_state, index, entry=None, column=0, stride=1) dataclass

Bases: BaseSpec

Values a symbol of a reduction stands for, one per reduced member or one shared value.

Parameters:

Name Type Description Default
is_state bool

Whether the values come from the state vector, as opposed to the extended parameter vector.

required
index int | Indices

The flat index of a shared value, or the flat index of the value of every reduced member.

required
entry EntrySpec | None

The layout entry the values belong to, or None for an element set.

None
column int

The component of the entry's member that the symbol stands for.

0
stride int

The distance between the values of two consecutive members in the vector.

1

per_member property

Whether the symbol has one value per reduced member.

ReductionSpec(call, kind, argument, condition, weights, over, function=None) dataclass

Bases: BaseSpec

Reduction call found in an expression, with its kind, argument, condition, weights, and group.

Parameters:

Name Type Description Default
call Expression

The unevaluated call.

required
kind str

'sum', 'mean', 'max', 'min', 'var', or 'count'.

required
argument Expression

The expression of one reduced member, 1 for a count.

required
condition Expression | None

The condition that selects the members, or None for all members.

required
weights object

The constant weight matrix, the symbol of a shaped parameter, or None.

required
over Expression | None

A symbol of the group to reduce over, or None for the group the argument reads.

required
function Callable[[AnyArray], object] | None

The function of the array of member values of a reduction of the kind 'function', or None.

None

RenewalRecordSpec(label, times, members, before, after, states) dataclass

Bases: BaseRecordSpec

Renewals of one renewal law that fired in one pass, each at the time of its member.

Parameters:

Name Type Description Default
label str

The name of the renewal law.

required
times Array

The time of every renewal.

required
members NDArray[intp]

The member of every renewal.

required
before Array

The states of every renewing member before its reset, one row per renewal and one column per state.

required
after Array

The states of every renewing member after its reset.

required
states tuple[str, ...]

The dotted state name, with the component of a vector state, of every column.

required

time property

Time of the last renewal of the pass.

RequirementSpec(time=(), space=()) dataclass

Bases: BaseSpec

What a part requires of the system it is part of: the classes of time and of space it runs in.

An empty field accepts any class.

Parameters:

Name Type Description Default
time tuple[type, ...]

The time classes the part runs in, such as (ContinuousTime,).

()
space tuple[type, ...]

The space classes the part runs in, such as (LatticeSpace,).

()

Examples:

>>> from skcomplex.core.spaces import ContinuousTime
>>> from skcomplex.specs import RequirementSpec
>>> RequirementSpec(time=(ContinuousTime,)).time
(<class 'skcomplex.core.spaces._continuous_time.ContinuousTime'>,)

RoleSpec(variadic=False, noise=False, optional=False) dataclass

Bases: BaseSpec

Spec of a role of an interaction, in the annotation of an argument of its constructor.

A plain role binds one element path, one group path, or one group member reference <group>[<index>]. A variadic role binds a sequence of them, and a noise role binds a WienerProcessSpec. An optional role may be bound to None, and then binds nothing.

Parameters:

Name Type Description Default
variadic bool

Whether the role binds a sequence of entries instead of one path.

False
noise bool

Whether the role binds a set of Wiener processes instead of a path.

False
optional bool

Whether the role may be bound to None, so it binds nothing.

False

Examples:

>>> from skcomplex.specs import RoleSpec
>>> RoleSpec(variadic=True).check().variadic
True

RunStateSpec(t, x, p, rng=None) dataclass

Bases: BaseSpec

State of a run at one time, which kernels and searches act at.

Parameters:

Name Type Description Default
t float

The time.

required
x Array

The state vector.

required
p Array

The parameter vector, extended with the reductions or the draws when a kernel reads them.

required
rng Generator | None

The random number generator of the run, or None for a kernel that draws nothing.

None

Examples:

>>> import numpy as np
>>> from skcomplex.specs import RunStateSpec
>>> RunStateSpec(0.0, np.ones(2), np.zeros(0)).x.tolist()
[1.0, 1.0]

SampledDrawSpec(start, rows, sample) dataclass

Bases: BaseSpec

Draw from a scipy.stats distribution that a stochastic map takes for every member at every step.

Parameters:

Name Type Description Default
start int

The index of the first value in the extended parameter vector.

required
rows int

The number of values, one per member.

required
sample Callable[[float, Array, Array, Generator], Array]

The function sample(t, x, q, rng) that returns the values, given the extended parameter vector q.

required

SamplerSpec(kind='metropolis', intensity=1.0, schedule='checkerboard') dataclass

Bases: BaseSpec

Spec of the acceptance of Monte Carlo moves at an intensity, with one sweep of the lattice per unit of time.

Parameters:

Name Type Description Default
kind str

'metropolis' to accept a change d of the objective with probability min(1, exp(-intensity * d)), 'glauber' with 1 / (1 + exp(intensity * d)), or 'heat-bath' to draw the new value among all values of a discrete move with weights exp(-intensity * objective).

'metropolis'
intensity object

The intensity, usually a parameter symbol so that it changes live.

1.0
schedule str

'checkerboard' to update the two sublattices of a square lattice in turn, 'colored' to update the classes of a proper coloring of the neighbour graph in turn, or 'random-sequential' to visit the sites one at a time in a random order.

'checkerboard'

Examples:

>>> from skcomplex.specs import SamplerSpec
>>> SamplerSpec('glauber', 2.0).check().schedule
'checkerboard'

SamplesSpec(series, labels, dt) dataclass

Bases: BaseSpec

Uniformly sampled series that a surrogate is fitted to.

Parameters:

Name Type Description Default
series list[Array]

The values of every series, one row per sample and one column per variable.

required
labels list[str]

The name of every variable.

required
dt float

The time between consecutive samples.

required

ScheduleSpec() dataclass

Bases: BaseSpec

Base of the specs of schedules of discrete time that a formalism defines, such as the phases of agents.

A subclass is a frozen dataclass of its own fields that overrides check.

SectorSpec(operator, value) dataclass

Bases: BaseSpec

Sector of an operator system: the basis states whose eigenvalue of a conserved diagonal operator equals a value.

Parameters:

Name Type Description Default
operator Callable[[SimpleNamespace], object]

A function of the system namespace that returns the conserved operator.

required
value float

The eigenvalue of the operator.

required

Examples:

>>> from skcomplex.specs import SectorSpec
>>> SectorSpec(lambda s: s.n, 2.0).check().value
2.0

SeriesSpec(times, values, labels) dataclass

Bases: BaseSpec

Named series on common times.

Parameters:

Name Type Description Default
times Array

The time of every frame.

required
values Array

One row per frame and one column per series.

required
labels list[str]

The name of every column.

required

SignatureSpec(kind, title, xlabel, ylabel, curves, values=dict(), xscale='linear', yscale='linear', points=False) dataclass

Bases: BaseSpec

Default analysis of one kind of data, ready to plot.

Parameters:

Name Type Description Default
kind DataKind

The kind of data analysed.

required
title str

The title of the figure.

required
xlabel str

The label of the horizontal axis.

required
ylabel str

The label of the vertical axis.

required
curves dict[str, tuple[Array, Array]]

A mapping from label to the abscissas and ordinates of every curve.

required
values dict[str, float]

The measured values worth stating, by name.

dict()
xscale str

'linear' or 'log'.

'linear'
yscale str

'linear' or 'log'.

'linear'
points bool

Whether the curves are drawn as points rather than lines.

False

SnapshotsSpec(times, ids, positions, velocities, directions, states=dict(), box=None, periodic=False, phases=None) dataclass

Bases: BaseSpec

Agents of one group at every frame, aligned on the agents present in every frame.

Parameters:

Name Type Description Default
times Array

The time of every frame.

required
ids NDArray[int64]

The id of every agent, in column order.

required
positions Array | None

The unwrapped positions, frames by agents by dimensions, or None without a space with coordinates.

required
velocities Array | None

The velocities, shaped like the positions, or None without them.

required
directions Array | None

The direction angles, frames by agents, or None without them.

required
states dict[str, NDArray[generic]]

Every other state of the agents, frames by agents.

dict()
box Array | None

The sides of the space, or None for an unbounded space.

None
periodic bool

Whether opposite sides of the box are joined.

False
phases Array | None

The phase angles, frames by agents, or None without them.

None

StableMatchingSpec(requester_preference=None, provider_preference=None, clearing='provider') dataclass

Bases: BaseSpec

Stable matching of Gale and Shapley, requesters proposing to providers that take as many as they offer units.

Requesters rank the providers whose limit they accept by requester_preference(requester, provider), by default the lower limit, and providers rank the requesters by provider_preference(provider, requester), by default the higher limit. The requester-optimal stable matching, from the hospital-resident solver of the matching library, pairs every requester with at most one provider, and each pair matches one unit at the value of the clearing rule.

Parameters:

Name Type Description Default
requester_preference Preference | None

The score of a provider for a requester, a function of their agent views, higher for preferred providers, or None for the lower limit.

None
provider_preference Preference | None

The score of a requester for a provider, a function of their agent views, higher for preferred requesters, or None for the higher limit.

None
clearing str

The value of a match, 'provider', 'requester', or 'midpoint'.

'provider'

Raises:

Type Description
ValidationError

The clearing rule is unknown, raised by check.

Examples:

>>> from skcomplex.specs import StableMatchingSpec
>>> StableMatchingSpec(clearing='requester').check().clearing
'requester'

StateSpec(domain=RR, vector=False, order=1, lags=0, initial=(), period=None, quantity=None, history=None, reference=None, role=None, tensor=None) dataclass

Bases: BaseSpec

Spec of a state of an element, in the annotation of an argument of its constructor.

The default of the argument is the initial value of the state. A state of order k has its k-th time derivative given by its rate laws, and a state with m lags keeps its past values for difference equations.

Parameters:

Name Type Description Default
domain object

The Sage set of the values of the state, such as RR, ZZ, RealSet.closed_open(0, oo), or FiniteEnumeratedSet(['S', 'I', 'R']), or None for a structure rewritten as a whole, such as a word, whose element checks it. A state of an agent with the domain None or object holds any hashable value, such as a tuple, a string, or a frozen set.

RR
vector bool

Whether the state has one component per dimension of the enclosing space.

False
order float

The order of the highest time derivative that laws give, an integer of at least 1, or a real number in (0, 1) for the Caputo derivative of a fractional order.

1
lags int

The number of past values the state keeps for difference equations, 0 for none.

0
initial Sequence[object]

The initial values of the derivatives of orders 1 to order - 1, or of the past values at steps -1 to -lags.

()
period float | None

The period that values of the state wrap around, such as 2 * pi for an angle, or None for none.

None
quantity str | None

The conserved quantity the state holds, such as 'money', or None. Only transfers change a tagged state.

None
history object

The values of the state before the start, which delayed laws read, a number or a function of time, or None to keep the initial value before the start.

None
reference str | None

The path of the agent group, relative to the element's system, a member of which the state names by its id, or None. A negative value names no member, nor does any value in a model without that group. The initial values of the group give the position of the member among the initial members of the referenced group, which the agent stepper turns into its id, and rules read the member with agent.referenced(state).

None
role str | None

What the state means in space or in a snapshot of agents or particles, 'position' for a coordinate or a vector of coordinates in space, 'site' for a vector of coordinates that places a member without making it a particle, 'direction' for the angle a member points along, 'phase' for the angle of a cycle a member goes through, 'velocity' for one component of a velocity or a vector of them, or None for any other state. A group is a particle group when a state has the role 'position', and the first derivative of that state is its velocity. Analyses read positions, directions, phases, and velocities from these roles alone, so a state named phase is no phase unless it says so. A vector state with the role 'position' or 'site' is the place of its element in a continuous space, on which the boundary of the space acts and from which neighbourhoods measure distances, and only 'position' makes a particle group.

None
tensor str | None

The symmetry of a rank-2 tensor state, 'full', 'symmetric', 'antisymmetric', or 'traceless', which means symmetric and traceless, or None for a state that is no tensor. The state stores its independent components, and laws read it as a Sage matrix whose dependent entries are written in terms of them.

None

Examples:

>>> from sage.all__sagemath_symbolics import oo
>>> from sage.sets.real_set import RealSet
>>> from skcomplex.specs import StateSpec
>>> spec = StateSpec(domain=RealSet.closed_open(0, oo)).check()
>>> 2.5 in spec.domain, -1 in spec.domain
(True, False)
>>> StateSpec(reference='banks').check().reference
'banks'
>>> StateSpec(tensor='traceless').check().tensor
'traceless'

StepSpec(t, x, p, until) dataclass

Bases: BaseSpec

Step of a run: the state at one time and the time a solver advances it to.

Parameters:

Name Type Description Default
t float

The current time.

required
x Array

The current state vector.

required
p Array

The parameter vector.

required
until float

The time to advance to.

required

Examples:

>>> import numpy as np
>>> from skcomplex.specs import StepSpec
>>> StepSpec(0.0, np.ones(1), np.zeros(0), 1.0).until
1.0

StructureStateSpec(structures=dict(), reporters=dict()) dataclass

Bases: BaseSpec

Structures of the elements a stepper keeps outside the state vector at one frame, with their measures.

Parameters:

Name Type Description Default
structures Mapping[str, object]

A mapping from element path to its structure, such as a word or a patch.

dict()
reporters Mapping[str, float]

A mapping from dotted reporter name, such as <path>.length, to its value.

dict()

Examples:

>>> from skcomplex.specs import StructureStateSpec
>>> StructureStateSpec(reporters={'cantor.length': 1.0}).reporters['cantor.length']
1.0

SupportSpec(time=frozenset(), space=frozenset(), laws=frozenset(), noise=frozenset(), orders=frozenset()) dataclass

Bases: BaseSpec

What a solver or a backend supports: the classes of time, space, and laws, and the kinds of noise and orders.

An empty field supports any class or kind. A class is supported when it is one of the classes of its field or a subclass of one, and None in the space field supports a system without a space.

Parameters:

Name Type Description Default
time Set[type]

The time classes supported.

frozenset()
space Set[type | None]

The space classes supported, with None for no space.

frozenset()
laws Set[type]

The law classes supported.

frozenset()
noise frozenset[NoiseKind]

The structures of Wiener processes supported.

frozenset()
orders frozenset[OrderKind]

The kinds of derivative orders supported.

frozenset()

Examples:

>>> from skcomplex.core.laws import NoiseLaw, RateLaw
>>> from skcomplex.specs import SupportSpec
>>> SupportSpec(laws={RateLaw}).missing('laws', [RateLaw, NoiseLaw])
['NoiseLaw']

missing(category, terms)

Return the names of the terms of a category that are not supported, sorted.

Parameters:

Name Type Description Default
category str

The name of the field, such as 'laws'.

required
terms Iterable[object]

The classes or kinds a system needs, with None for a system without a space.

required

Returns:

Name Type Description
missing list[str]

The names of the unsupported terms.

Source code in src/skcomplex/specs/_support_spec.py
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
def missing(self, category: str, terms: Iterable[object]) -> list[str]:
    """Return the names of the terms of a category that are not supported, sorted.

    Args:
        category:
            The name of the field, such as `'laws'`.

        terms:
            The classes or kinds a system needs, with `None` for a system without a space.

    Returns:
        missing:
            The names of the unsupported terms.
    """
    found = {getattr(term, '__name__', str(term)) for term in terms if not self._supports(category, term)}
    return sorted(found)

SymmetrySpec(label, generator) dataclass

Bases: BaseSpec

Spec of a continuous symmetry of a system, the infinitesimal variation of the coordinates it moves.

The generator is a function of the namespace of the system, where s.<element>.<state> is the symbol of a state, that maps the path of every coordinate it moves, such as 'body.q', to its infinitesimal variation dq, an expression for a scalar state or a vector for a vector state.

Parameters:

Name Type Description Default
label str

The label of the symmetry.

required
generator Callable[[SimpleNamespace], Mapping[str, object]]

A function of the namespace of the system that returns the variation of every coordinate it moves.

required

Raises:

Type Description
ValidationError

The label is empty, or the generator is not callable.

Examples:

>>> from sage.all__sagemath_symbolics import vector
>>> from skcomplex.specs import SymmetrySpec
>>> rotation = SymmetrySpec('rotation', lambda s: {'body.q': vector([-s.body.q[1], s.body.q[0]])})
>>> rotation.check().label
'rotation'

TableSpec(mapping, default=0.0, states=None) dataclass

Bases: BaseSpec

Rule given by the next value of every neighbourhood pattern of integer states 0 to states - 1.

Parameters:

Name Type Description Default
mapping Mapping[tuple[int, ...], float]

A mapping from pattern, a tuple of values in neighbourhood order, to the next value.

required
default float

The next value of patterns the mapping leaves out.

0.0
states int | None

The number of state values, or None for one more than the largest value in the patterns.

None

Examples:

>>> from skcomplex.specs import TableSpec
>>> TableSpec({(1, 1): 1}).n_states
2

n_states property

Number of state values, the given states or one more than the largest value in the patterns, at least 2.

TableValuesSpec(table, positions, parameters, time) dataclass

Bases: BaseSpec

Values of selected entries of a table of numbers or parameter expressions at a parameter vector.

Parameters:

Name Type Description Default
table AnyArray

The table, a float array or an object array of Sage expressions.

required
positions tuple[Indices, ...]

The indices of the selected entries, one array per dimension.

required
parameters Mapping[Expression, int]

The flat index in the parameter vector of every parameter symbol the selected entries read.

required
time Expression

The time symbol.

required

TensorSpec(symmetry, n_dim) dataclass

Bases: BaseSpec

Independent components of a rank-2 tensor of one symmetry in a space of two or three dimensions.

Parameters:

Name Type Description Default
symmetry str

'full', 'symmetric', 'antisymmetric', or 'traceless', which means symmetric and traceless.

required
n_dim int

The number of dimensions of the space.

required

Raises:

Type Description
ValidationError

The symmetry is unknown or the space does not have two or three dimensions.

Examples:

>>> from skcomplex.specs import TensorSpec
>>> tensor = TensorSpec('traceless', 2).check()
>>> tensor.names
('xx', 'xy')
>>> tensor.array_of([1.0, 2.0]).tolist()
[[1.0, 2.0], [2.0, -1.0]]

basis cached property

Tensors of the independent components, with one tensor per component on the first axis.

indices cached property

Row and column of every independent component, in row order.

names cached property

Name of every independent component, such as xx and xy.

array_of(components)

Return the arrays of tensors of independent components on the last axis.

Parameters:

Name Type Description Default
components ArrayLike

The independent components on the last axis.

required

Returns:

Name Type Description
tensors Array

The tensors on the last two axes.

Examples:

>>> from skcomplex.specs import TensorSpec
>>> TensorSpec('antisymmetric', 2).array_of([3.0]).tolist()
[[0.0, 3.0], [-3.0, 0.0]]
Source code in src/skcomplex/specs/_tensor_spec.py
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
def array_of(self, components: npt.ArrayLike) -> Array:
    """Return the arrays of tensors of independent components on the last axis.

    Args:
        components:
            The independent components on the last axis.

    Returns:
        tensors:
            The tensors on the last two axes.

    Examples:
        >>> from skcomplex.specs import TensorSpec
        >>> TensorSpec('antisymmetric', 2).array_of([3.0]).tolist()
        [[0.0, 3.0], [-3.0, 0.0]]
    """
    return np.tensordot(np.asarray(components, dtype=float), self.basis, axes=1)

components_of(value)

Return the independent components of a numeric matrix.

Parameters:

Name Type Description Default
value object

A matrix of numbers, such as a nested sequence, a NumPy array, or a Sage matrix.

required

Returns:

Name Type Description
components Array

The independent components.

Raises:

Type Description
ValidationError

The value is not a matrix of the shape and the symmetry of the tensor.

Examples:

>>> from skcomplex.specs import TensorSpec
>>> TensorSpec('symmetric', 2).components_of([[1, 2], [2, 3]]).tolist()
[1.0, 2.0, 3.0]
Source code in src/skcomplex/specs/_tensor_spec.py
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
def components_of(self, value: object) -> Array:
    """Return the independent components of a numeric matrix.

    Args:
        value:
            A matrix of numbers, such as a nested sequence, a NumPy array, or a Sage matrix.

    Returns:
        components:
            The independent components.

    Raises:
        ValidationError:
            The value is not a matrix of the shape and the symmetry of the tensor.

    Examples:
        >>> from skcomplex.specs import TensorSpec
        >>> TensorSpec('symmetric', 2).components_of([[1, 2], [2, 3]]).tolist()
        [1.0, 2.0, 3.0]
    """
    array = np.asarray(value.numpy() if isinstance(value, Matrix) else value, dtype=float)
    if array.shape != (self.n_dim, self.n_dim):
        error_msg = f'The value has the shape {array.shape}, but the tensor is {self.n_dim} by {self.n_dim}.'
        raise ValidationError(error_msg)
    components = np.asarray([array[row, column] for row, column in self.indices])
    if not np.allclose(self.array_of(components), array):
        error_msg = f'The matrix {array.tolist()} does not have the symmetry {self.symmetry!r}.'
        raise ValidationError(error_msg)
    return components

matrix_of(components)

Return the symbolic matrix of independent components, with the dependent entries written in terms of them.

Parameters:

Name Type Description Default
components Iterable[object]

The expressions of the independent components.

required

Returns:

Name Type Description
matrix Matrix

The matrix over the symbolic ring.

Examples:

>>> from sage.all__sagemath_symbolics import var
>>> from skcomplex.specs import TensorSpec
>>> TensorSpec('traceless', 2).matrix_of(var('a, b'))
[ a  b]
[ b -a]
Source code in src/skcomplex/specs/_tensor_spec.py
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
def matrix_of(self, components: Iterable[object]) -> Matrix:
    """Return the symbolic matrix of independent components, with the dependent entries written in terms of them.

    Args:
        components:
            The expressions of the independent components.

    Returns:
        matrix:
            The matrix over the symbolic ring.

    Examples:
        >>> from sage.all__sagemath_symbolics import var
        >>> from skcomplex.specs import TensorSpec
        >>> TensorSpec('traceless', 2).matrix_of(var('a, b'))
        [ a  b]
        [ b -a]
    """
    total = matrix(SR, self.n_dim, self.n_dim)
    for component, unit in zip(components, self.basis, strict=True):
        total += SR(component) * matrix(SR, unit.tolist())
    return total

principal_of(components)

Return the principal axis and the scalar order of symmetric tensors of independent components.

The principal axis is the eigenvector of the largest eigenvalue of the traceless part. The scalar order is that eigenvalue times n_dim / (n_dim - 1), so a tensor S (n n - I / n_dim) has the order S.

Parameters:

Name Type Description Default
components ArrayLike

The independent components on the last axis.

required

Returns:

Name Type Description
axes Array

The axes, unit vectors on the last axis, whose sign has no meaning.

orders Array

The scalar orders.

Raises:

Type Description
ValidationError

The tensor is not symmetric.

Examples:

>>> from skcomplex.specs import TensorSpec
>>> axes, orders = TensorSpec('traceless', 2).principal_of([0.5, 0.0])
>>> abs(axes).round(6).tolist(), float(orders)
([1.0, 0.0], 1.0)
Source code in src/skcomplex/specs/_tensor_spec.py
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
def principal_of(self, components: npt.ArrayLike) -> tuple[Array, Array]:
    """Return the principal axis and the scalar order of symmetric tensors of independent components.

    The principal axis is the eigenvector of the largest eigenvalue of the traceless part. The scalar order is that
    eigenvalue times `n_dim / (n_dim - 1)`, so a tensor `S (n n - I / n_dim)` has the order `S`.

    Args:
        components:
            The independent components on the last axis.

    Returns:
        axes:
            The axes, unit vectors on the last axis, whose sign has no meaning.

        orders:
            The scalar orders.

    Raises:
        ValidationError:
            The tensor is not symmetric.

    Examples:
        >>> from skcomplex.specs import TensorSpec
        >>> axes, orders = TensorSpec('traceless', 2).principal_of([0.5, 0.0])
        >>> abs(axes).round(6).tolist(), float(orders)
        ([1.0, 0.0], 1.0)
    """
    if self.symmetry not in {'symmetric', 'traceless'}:
        error_msg = f'A tensor of the symmetry {self.symmetry!r} has no principal axes. Use a symmetric tensor.'
        raise ValidationError(error_msg)
    tensors = self.array_of(components)
    means = np.trace(tensors, axis1=-2, axis2=-1) / self.n_dim
    values, vectors = np.linalg.eigh(tensors - means[..., None, None] * np.eye(self.n_dim))
    return vectors[..., -1], values[..., -1] * self.n_dim / (self.n_dim - 1)

TopologyRequestSpec(kind, edges=1, toward=None, keep='source', layer=None, values=(), hyperedge=None) dataclass

Bases: BaseSpec

Spec of a change of the topology of a network that a law requests for every member or edge it runs for.

A request is the target of an UpdateLaw, whose value is the probability that it fires at every step for the member or edge the law runs for, or of a JumpLaw, as JumpLaw(rate, {request: 1}), which fires it at the rate. The stepper applies the requests that fire after the step, in the order of the members and edges. A request on edges, 'add-edge', 'remove-edge', or 'rewire', adds or removes members of the variable group on the edges of its layer, and a request on nodes, 'add-node' or 'remove-node', adds or removes members of every variable group on the nodes of the network. New ends are drawn among the nodes present that are not yet joined to the node, with probability proportional to toward.

Parameters:

Name Type Description Default
kind str

'add-edge', 'remove-edge', 'rewire', 'add-node', or 'remove-node'.

required
edges int

The number of edges a new node or a node adding edges joins to other nodes.

1
toward Callable[[SimpleNamespace], object] | None

A function of the namespace of a candidate node that returns its weight for a new end, such as lambda node: neighbors(1) for the degree of preferential attachment, or None for equal weights.

None
keep str

The end of an edge that a rewiring keeps, 'source' or 'target'.

'source'
layer str | None

The layer whose edges the request changes, or None for the graph of the network.

None
values tuple[tuple[str, object], ...]

The initial states of a new node or edge as pairs of a state name and a value, or a function of the random number generator that draws the value for every new node or edge, which default to the defaults of the element type.

()
hyperedge int | None

The size of the hyperedge a new node forms with existing nodes, joining each of them by an edge in place of edges, or None for no hyperedge. The first two existing members are the ends of an edge drawn uniformly, and further members are drawn by toward.

None

Examples:

>>> from skcomplex.core.laws import UpdateLaw
>>> from skcomplex.specs import TopologyRequestSpec
>>> UpdateLaw(TopologyRequestSpec('rewire', keep='target').check(), 0.1).check().target.keep
'target'

TotalisticSpec(rule, default=0.0, states=2) dataclass

Bases: BaseSpec

Rule given by the next value of every sum of the neighbourhood values.

Parameters:

Name Type Description Default
rule Mapping[int, float] | Callable[[IntArray], ArrayLike]

A mapping from sum to next value, or a function of the sums that returns the next values.

required
default float

The next value of sums a mapping leaves out.

0.0
states int

The number of state values 0 to states - 1, which bounds the sums.

2

Examples:

>>> from skcomplex.specs import TotalisticSpec
>>> TotalisticSpec(lambda total: total > 4).states
2

ValidationReportSpec(issues=()) dataclass

Bases: BaseSpec

Every issue that a compiler found in a system, its solver, and its backend.

check() emits the warnings of the report and raises one error that lists its errors, so a valid report passes its check.

Parameters:

Name Type Description Default
issues tuple[IssueSpec, ...]

The issues, in the order they were found.

()

Examples:

>>> from skcomplex.engine.compile import PassCompiler
>>> from skcomplex.core.system import System
>>> PassCompiler().check().prepare(System()).report_.ok
True

errors property

Return the issues that stop compilation.

ok property

Check whether the report holds no error.

warnings property

Return the issues that do not stop compilation.

VariableSpec(kind, domain=RR, vector=False, order=1, lags=0, initial=(), period=None, derivative_of=None, lag_of=None, index=0, variadic=False, noise=False, optional=False, per=None, quantity=None, history=None, adaptive=False, bounds=None, reference=None, role=None, shape=None, tensor=None) dataclass

Bases: BaseSpec

Declaration of a state, a parameter, or a role of a part, as the compiler reads it.

A state of order k adds the companion states <name>_d1 to <name>_d<k-1> that hold its derivatives, and a state with m lags adds <name>_lag1 to <name>_lag<m> that hold its past values.

Parameters:

Name Type Description Default
kind VariableKind

Whether the argument is a state, a parameter, or a role.

required
domain object

The Sage set of the values, or None for a structure rewritten as a whole.

RR
vector bool

Whether the variable has one component per dimension of the enclosing space.

False
order float

The order of the highest time derivative that laws give for a state.

1
lags int

The number of past values a state keeps.

0
initial tuple[object, ...]

The initial values of the derivatives of orders 1 to order - 1, or of the lags 1 to lags.

()
period float | None

The period that values of the state wrap around, or None.

None
derivative_of str | None

The state whose derivative a companion state holds, or None.

None
lag_of str | None

The state whose past value a companion state holds, or None.

None
index int

The order of the derivative or the lag that a companion state holds.

0
variadic bool

Whether a role binds a sequence of entries instead of one path.

False
noise bool

Whether a role binds a set of Wiener processes.

False
optional bool

Whether a role may be bound to None, so it binds nothing.

False
per str | None

The variadic role whose entries a parameter holds one value for, or None.

None
quantity str | None

The conserved quantity a state holds, or None.

None
history object

The values of a state before the start, or None.

None
adaptive bool

Whether a parameter is adaptive, which laws may change.

False
bounds tuple[float, float] | None

The lower and upper bound of an adaptive parameter, or None.

None
reference str | None

The path of the agent group a member of which a state names by its id, or None.

None
shape tuple[str, ...] | None

The names of the roles whose group sizes give the shape of a parameter, or None.

None
tensor str | None

The symmetry of a rank-2 tensor state, or None.

None

derivatives property

Number of companion states that hold the derivatives of orders 1 to order - 1.

is_fractional property

Whether the order of the state is not an integer, so its rate laws give a Caputo derivative.

is_place property

Whether a vector state is the place of its element in a continuous space, by its role.

VisualSpec(kind='scalars', options=dict()) dataclass

Bases: BaseSpec

Visual of an element and the options it is built with.

Parameters:

Name Type Description Default
kind str | type

The name of a visual of the engine, such as 'points', or a visual class, such as one a model package defines on BaseVisual.

'scalars'
options dict[str, object]

The keyword arguments of the visual.

dict()

Examples:

>>> from skcomplex.specs import VisualSpec
>>> VisualSpec('points', {'position': 'x'}).kind
'points'

WienerBlockSpec(start, size, factor) dataclass

Bases: BaseSpec

Correlated Wiener processes of one WienerProcessSpec, a contiguous block of the processes of a problem.

Parameters:

Name Type Description Default
start int

The index of the first process of the block.

required
size int

The number of processes of the block.

required
factor NDArray[float64]

The factor L with L L^T = C of the covariance C of the block.

required

WienerProcessSpec(label, dimension=1, covariance=None) dataclass

Bases: BaseSpec

Spec of a set of Wiener processes whose increments over a step h have the covariance h C.

An interaction binds the processes through a role declared with RoleSpec(noise=True), and its noise laws name them through the handle namespace.<role>.dW, a symbol for one process and a vector of symbols for several, so namespace.<role>.dW[k] names process k. Interactions of one system that bind processes of one label share them, so laws that name one process share its increment.

Parameters:

Name Type Description Default
label str

The label of the processes, unique among the parts of the system of the interactions that bind them.

required
dimension int

The number of processes.

1
covariance object

The constant covariance matrix C of the processes, symmetric and positive semidefinite of size dimension, or None for the identity.

None

Examples:

>>> from skcomplex.specs import WienerProcessSpec
>>> WienerProcessSpec('shared', dimension=2, covariance=((1.0, 0.5), (0.5, 1.0))).check().dimension
2