Julia sets
The filled Julia set of z -> z^2 + c, the starting points whose orbit stays bounded (Dilão 2023 §5.5).
- Name:
julia - Field:
mathematics/fractals - Formalism: discrete map
- References: Dilão 2023
Factory
@register_model(
field='mathematics/fractals',
tags=('fractal', 'complex', 'map', 'lattice', 'escape time'),
references=('Dilão 2023',),
defaults={'until': 100, 'dt': 1},
)
def julia(
c: complex = -0.8 + 0.156j,
shape: Sequence[int] = (240, 320),
*,
window: Window = JULIA_WINDOW,
radius: float = 2.0,
) -> System:
"""Return the filled Julia set of `z -> z^2 + c`, the starting points whose orbit stays bounded (Dilão 2023 §5.5).
Every site holds one starting point `z` of the window and iterates the map with the same constant `c`, and `n`
counts the steps the orbit stays within the escape radius. For `c` in the Mandelbrot set the filled Julia set is
connected, and outside it the set breaks into dust.
Args:
c:
The constant of the map.
shape:
The number of sites along the imaginary and the real axis.
window:
The smallest and largest real part, then the smallest and largest imaginary part, of the starting points.
radius:
The escape radius, at least 2 and at least `|c|`, so escaped orbits never return.
Returns:
system:
The model, with the field `plane`, its orbits `plane.z`, and its escape times `plane.n`.
Examples:
>>> from skcomplex.models.mathematics.fractals import julia
>>> julia(0.0, (3, 3), window=(-1, 1, -1, 1)).elements[0].values['z'][0].tolist()
[(-1+1j), 1j, (1+1j)]
"""
points = _plane(shape, window)
return _escape_field(shape, points, complex(c), radius)
Components
class QuadraticMapElement(Element):
"""Complex quadratic map `z' = z^2 + c` while `|z|` stays within the escape radius, with a count of its steps.
Args:
label:
The label of the element.
visual:
How the element is drawn, or `None` for `default_visual_`.
z:
The initial point.
n:
The initial number of steps within the escape radius.
c:
The constant of the map.
radius:
The escape radius.
Examples:
>>> from skcomplex.models.mathematics.fractals import QuadraticMapElement
>>> QuadraticMapElement('point', c=0.25).c
0.25
"""
def __init__(
self,
label: str,
visual: VisualSpec | None = None,
*,
z: Annotated[object, StateSpec(domain=CC)] = 0.0,
n: Annotated[object, StateSpec(domain=NN)] = 0.0,
c: Annotated[object, ParameterSpec(domain=CC)] = 0.0,
radius: Annotated[object, ParameterSpec(domain=RealSet.open(0, oo))] = 2.0,
) -> None:
super().__init__(label, visual=visual)
self.z = z
self.n = n
self.c = c
self.radius = radius
def _get_laws(self, s: SimpleNamespace) -> list[BaseLaw]:
"""Return the next point, which stays once it escaped, and the next count.
Args:
s:
The namespace of the symbols the laws can use.
Returns:
laws:
The laws of the element.
"""
return [
UpdateLaw(s.z, where(abs(s.z) <= s.radius, s.z**2 + s.c, s.z)),
UpdateLaw(s.n, s.n + where(abs(s.z) <= s.radius, 1, 0)),
]
Equations
plane.z[i].real: z_plane_re(t + 1) == where(sqrt(z_plane_im(t)^2 + z_plane_re(t)^2) <= radius_plane, -z_plane_im(t)^2 + z_plane_re(t)^2 + c_plane_re, z_plane_re(t))
plane.z[i].imag: z_plane_im(t + 1) == where(sqrt(z_plane_im(t)^2 + z_plane_re(t)^2) <= radius_plane, 2*z_plane_im(t)*z_plane_re(t) + c_plane_im, z_plane_im(t))
plane.n[i]: n_plane(t + 1) == n_plane(t) + where(sqrt(z_plane_im(t)^2 + z_plane_re(t)^2) <= radius_plane, 1, 0)
