Aggregate-averaging synchronization
Two logistic maps coupled by aggregate averaging, which synchronize their chaos for strong coupling.
- Name:
aggregate_averaging_synchronization - Field:
physics/synchronization - Formalism: discrete map
- References: Gros 2015
Factory
@register_model(
field='physics/synchronization',
tags=('synchronization', 'chaos', 'map', 'logistic map'),
references=('Gros 2015',),
defaults={'until': 50, 'dt': 1},
)
def aggregate_averaging_synchronization(
x1: float = 0.3,
x2: float = 0.6,
*,
r: float = 4.0,
kappa: float = 0.4,
) -> System:
"""Return two logistic maps coupled by aggregate averaging, which synchronize their chaos for strong coupling.
Each map iterates on the aggregate of its own value and the other's, `x_i(t + 1) = r a_i (1 - a_i)` with
`a_1 = (1 - kappa) x_1 + kappa x_2` and `a_2 = (1 - kappa) x_2 + kappa x_1`. The synchronized orbit is stable for
`kappa > (r - 1) / (2 r)`, which is `3 / 8` for `r = 4`, and the maps agree in one step for `kappa = 1 / 2`.
Args:
x1:
The initial value of the first map.
x2:
The initial value of the second map.
r:
The growth rate of the logistic map.
kappa:
The coupling strength.
Returns:
system:
The model, with the values `first.x` and `second.x`.
Examples:
>>> from skcomplex.models.physics.synchronization import aggregate_averaging_synchronization
>>> aggregate_averaging_synchronization(kappa=0.1).interactions[0].kappa
0.1
"""
return System(
elements=[LogisticUnitElement('first', x=x1), LogisticUnitElement('second', x=x2)],
interactions=[
AggregateAveragingInteraction(f'averaging_{target}', source=source, target=target, r=r, kappa=kappa)
for source, target in (('second', 'first'), ('first', 'second'))
],
)
Components
class LogisticUnitElement(Element):
"""Value `x` in `[0, 1]` of a logistic map, which maps of the coupling iterate.
Args:
label:
The label of the unit.
visual:
How the unit is drawn, or `None` for `default_visual_`.
x:
The initial value.
Attributes:
default_visual_:
The visual of the unit when it sets none.
Examples:
>>> from skcomplex.models.physics.synchronization import LogisticUnitElement
>>> LogisticUnitElement('unit').x
0.3
"""
def __init__(
self,
label: str,
visual: VisualSpec | None = None,
*,
x: Annotated[float, StateSpec()] = 0.3,
) -> None:
super().__init__(label, visual=visual)
self.x = x
class AggregateAveragingInteraction(MapInteraction):
"""Logistic map of an aggregate, `x_t(t + 1) = r a (1 - a)` with `a = (1 - kappa) x_t + kappa x_s`.
Args:
label:
The label of the interaction, unique among the parts of its system.
source:
The path of the unit whose value the aggregate reads.
target:
The path of the unit whose value the map sets.
r:
The growth rate of the logistic map.
kappa:
The weight of the source in the aggregate.
Examples:
>>> from types import SimpleNamespace
>>> from sage.all__sagemath_symbolics import var
>>> from skcomplex.models.physics.synchronization import AggregateAveragingInteraction
>>> averaging = AggregateAveragingInteraction('averaging', source='a', target='b').check().prepare()
>>> source, target = SimpleNamespace(x=var('u')), SimpleNamespace(x=var('v'))
>>> namespace = SimpleNamespace(source=source, target=target, r=4, kappa=var('kappa'))
>>> [law.value.factor() for law in averaging.run(namespace).laws_]
[-4*(kappa*u - kappa*v + v)*(kappa*u - kappa*v + v - 1)]
"""
def __init__(
self,
label: str,
*,
source: Annotated[str, RoleSpec()],
target: Annotated[str, RoleSpec()],
r: Annotated[float, ParameterSpec(domain=RealSet.closed_open(0, oo))] = 4.0,
kappa: Annotated[float, ParameterSpec(domain=RealSet.closed_open(0, oo))] = 0.4,
) -> None:
super().__init__(label, target=target, state='x', function=self._average)
self.source = source
self.r = r
self.kappa = kappa
def _average(self, namespace: SimpleNamespace) -> Expression:
"""Return the logistic map `r a (1 - a)` of the aggregate `a = (1 - kappa) x_t + kappa x_s`."""
aggregate = (1 - namespace.kappa) * namespace.target.x + namespace.kappa * namespace.source.x
return namespace.r * aggregate * (1 - aggregate)
Equations
first.x: x_first(t + 1) == -((kappa_averaging_first - 1)*x_first(t) - kappa_averaging_first*x_second(t) + 1)*((kappa_averaging_first - 1)*x_first(t) - kappa_averaging_first*x_second(t))*r_averaging_first
second.x: x_second(t + 1) == -(kappa_averaging_second*x_first(t) - (kappa_averaging_second - 1)*x_second(t))*(kappa_averaging_second*x_first(t) - (kappa_averaging_second - 1)*x_second(t) - 1)*r_averaging_second