This is a simple python project to render lyapunov fractals. It relies on numba cuda kernels for relatively fast fractal generation.
As this project uses numba-cuda, you need a CUDA-enabled NVIDIA graphics card with Compute Capability 3.5 or greater.
Optionally, you can create a virtual environement with
python -m venv .venv
.venv\Scripts\activate
Then run pip install -r requirements.txt
to install all the necessary packages.
Finally, run python ./gui.py
to start the user interface.
Running the file
gui.py
opens a window where you can modify the fractal parameters:
- Press the
left mouse button
to zoom - Press the
right mouse button
to dezoom - Press
space
to increase the$z$ coordinate of the fractal - Press
backspace
to decrease the$z$ coordinate of the fractal - Press
c
to cycle the fractal pattern.
Running the file generate_fractal_image.py
creates an image of a fractal and displays it to the screen.
Running the file generate_fractal_video.py
creates and stores a gif cycling through slices of a 3D lyapunov fractal in the
In the following section we will discuss 2D lyapunov fractals. The generalization to higher dimensions is quite simple as you just need to allow more coordinates in the pattern, and compute the modified logistic sequence values accordingly.
A 2D lyapunov fractal is created by computing the lyapunov exponent for each screen pixel of a modified logistic sequence.
We call pattern a chain of "x" and "y" characters, such as "xyyyxyxx".
Given a pattern and a value for
where
For a small enough initial distance
We can therefore define the Lyapunov exponent
To compute the Lyapunov exponent numerically, we can truncate the series at a large value of
So briefly, the lyapunov exponent
We first associate the pixels of the screen to a grid of coordinates between 0 and 4 (this is a range on which the logistic sequence is stable).
Then for each pixel on the screen:
- We get the
$x$ and$y$ coordinates corresponding to the pixel position. - We compute the lyapunov exponent of the sequence
$(f^N(0.5))$ - Then, we color the pixel according to the value of the lyapunov exponent.
This algorithm is generalizable to higher dimensions than 2 by adding new letters in the logistic sequence pattern, and cycling
In our case,
Interestingly, the diagonal
Here is the kernel that runs for each image pixel:
for i in range(num_iter):
r = (x, y, z)[sequence[i%len_sequence]]
x_n = r*x_n*(1-x_n)
lambda_N += log(abs(r*(1-2*x_n)))
space[pos] = lambda_N
You can set the fractal parameters of ComputeFractals
using the set_parameters
method, which can take in any combination of:
x_min
,x_max
,y_min
,y_max
,z
define the region in which fractals will be computed. These values need to be between 0 and 4.size
: the size of the generated images in pixels.colors
: a list of hex colors such as "#ff0ed6".color_resolution
: how many different shades of the color list are used.pattern
: a string of "x", "y", and "z". The pattern defines which fractal is generated.num_iter
: defines at which precision the pixel values are computed.
Calling compute_fractal()
then computes a slice of a 3D lyapunov fractal using the current parameters.
apply_gradient()
then applies a color gradient and returns an image.