Fractales aleatorios

Antes que nada, ¿qué son fractales?


1. Fractales

  • La geometría fractal es un campo de las matemáticas que tiene lugar a partir de los años setenta, y fue desarrollada principalmente por Benoit Mandelbrot.

  • La geometría elemental que aprendimos en la escuela se trataba de estudiar (y hacer) formas o figuras. Pues bien, la geometría fractal no es distinta.

  • Mientras que en geometría clásica las formas son suaves (círculos, triángulos, etcétera), las formas que produce la geometría fractal es tosca e infinitamente compleja.

Bueno, ¿y cuál es su importancia?

  1. El proceso por el cual se obtienen formas fractales es impresionantemente simple y completamente diferente al seguido en geometría clásica. Mientras la geometría clásica se usan fórmulas para definir una forma, la geometría fractal usa iteración. Básicamente, podríamos decir que los fractales son imágenes de sistemas dinámicos.

  2. Las formas fractales se parecen mucho a formas encontradas en la naturaleza. Este impresionante hecho es difícil de ignorar. Como sabemos no existen círculos perfectos en la naturaleza, ni cuadrados perfectos. No es solo eso, el solo mirar los árboles, ríos o montañas, y no se encuentra una forma que sea descrita por una fórmula. Sin embargo, usando fórmulas simples iteradas muchas veces, la geometría fractal puede modelar esos fenómenos con alta precisión. Si puedes usar matemáticas simples para modelar el mundo, vas por buen camino.


La figura de la derecha (planta verde) corresponde a un helecho. El matemático británico Michael Barnsley fue quien primero describió un fractal que representa impresionantemente bien estas plantas, en su libro 'Fractals Everywhere'.

2. Fractal helecho de Barnsley

El helecho de Barnsley es un fractal que usa cuatro transformaciones afines para generar los nuevos puntos. En la escogencia de cuál transformación usar para generar el siguiente punto es donde entra el componente probabilístico.

Este fractal se puede describir de la siguiente manera:

$$\left[\begin{array}{c}x_{k+1}\\ y_{k+1}\end{array}\right]=\left[\begin{array}{cc}a_i & b_i \\ c_i & d_i\end{array}\right]\left[\begin{array}{c}x_k\\ y_k\end{array}\right]+\left[\begin{array}{c}e_i\\f_i\end{array}\right],$$

donde $a_i$, $b_i$, $c_i$, $d_i$, $e_i$ y $f_i$ son coeficientes que dependen de la variable aleatoria $i\in\left\lbrace 0,1,2,3\right\rbrace$. Las condiciones iniciales son $x_0=y_0=0$.

Las probabilidades de ocurrencia de cada valor de $i$ son $P\left\lbrace i=0\right\rbrace=p_0=0.01$, $P\left\lbrace i=1\right\rbrace=p_1=0.85$, $P\left\lbrace i=2\right\rbrace=p_2=0.07$ y $P\left\lbrace i=3\right\rbrace=p_3=0.07$ (notar que la suma de las probabilidades es 1).

Todas las anteriores constantes se resume en la siguiente tabla (matriz):


In [3]:
import pandas as pd
import numpy as np

In [4]:
i = np.arange(4)

df = pd.DataFrame(index=i,columns=['$a_i$', '$b_i$', '$c_i$', '$d_i$', '$e_i$', '$f_i$', '$p_i$', 'Porción generada'], dtype='float')
df.index.name = "$i$"

df['$a_i$'] = [0.0, 0.85, 0.2, -0.15]
df['$b_i$'] = [0.0, 0.04, -0.26, 0.28]
df['$c_i$'] = [0.0, -0.04, 0.23, 0.26]
df['$d_i$'] = [0.16, 0.85, 0.22, 0.24]
df['$e_i$'] = [0.0, 0.0, 0.0, 0.0]
df['$f_i$'] = [0.0, 1.6, 1.6, 0.44]
df['$p_i$'] = [0.01, 0.85, 0.07, 0.07]
df['Porción generada'] = ['Tallo', 'Follaje cada vez más pequeño', 'Ramas izquierda', 'Ramas derecha']

df.round(2)


Out[4]:
$a_i$ $b_i$ $c_i$ $d_i$ $e_i$ $f_i$ $p_i$ Porción generada
$i$
0 0.00 0.00 0.00 0.16 0.0 0.00 0.01 Tallo
1 0.85 0.04 -0.04 0.85 0.0 1.60 0.85 Follaje cada vez más pequeño
2 0.20 -0.26 0.23 0.22 0.0 1.60 0.07 Ramas izquierda
3 -0.15 0.28 0.26 0.24 0.0 0.44 0.07 Ramas derecha

Con la anterior descripción, generemos el helecho de Barnsley con un código en python...


In [5]:
# Importamos librerías
import matplotlib.pyplot as plt
import random

In [6]:
# Punto inicial
x, y = [0.0], [0.0]

In [7]:
# Matriz de Barnsley
mat_Barnsley = np.array([[0.0, 0.0, 0.0, 0.16, 0.0, 0.0, 0.01],
                        [0.85, 0.04, -0.04, 0.85, 0.0, 1.6, 0.85],
                        [0.2, -0.26, 0.23, 0.22, 0.0, 1.6, 0.07],
                        [-0.15, 0.28, 0.26, 0.24, 0.0, 0.44, 0.07]])
mat_Barnsley


Out[7]:
array([[ 0.  ,  0.  ,  0.  ,  0.16,  0.  ,  0.  ,  0.01],
       [ 0.85,  0.04, -0.04,  0.85,  0.  ,  1.6 ,  0.85],
       [ 0.2 , -0.26,  0.23,  0.22,  0.  ,  1.6 ,  0.07],
       [-0.15,  0.28,  0.26,  0.24,  0.  ,  0.44,  0.07]])

In [18]:
# Generación de puntos con las frecuencias dadas
for k in range(100000):
    p = random.random()
    if p <= mat_Barnsley[0, 6]:
        i = 0
    elif p <= mat_Barnsley[0, 6] + mat_Barnsley[1,6]:
        i = 1
    elif p <= mat_Barnsley[0, 6] + mat_Barnsley[1,6] + mat_Barnsley[2, 6]:
        i = 2
    else:
        i = 3
    
    x.append(mat_Barnsley[i, 0]*x[-1] + mat_Barnsley[i, 1]*y[-1] + mat_Barnsley[i, 4])
    y.append(mat_Barnsley[i, 2]*x[-2] + mat_Barnsley[i, 3]*y[-1] + mat_Barnsley[i, 5])

plt.figure(figsize=(10,10))
plt.scatter(x, y, c='g', s = 0.2)
plt.show()


Actividad: jugando con los coeficientes de la transformación es posible crear mutaciones del helecho.

Un experimentador dió con una tabla de coeficientes que produce otro helecho que se ve muy parecido a la naturaleza. La tabla es la siguiente:


In [19]:
i = np.arange(4)

df = pd.DataFrame(index=i,columns=['$a_i$', '$b_i$', '$c_i$', '$d_i$', '$e_i$', '$f_i$', '$p_i$', 'Porción generada'], dtype='float')
df.index.name = "$i$"

df['$a_i$'] = [0.0, 0.95, 0.035, -0.04]
df['$b_i$'] = [0.0, 0.005, -0.2, 0.2]
df['$c_i$'] = [0.0, -0.005, 0.16, 0.16]
df['$d_i$'] = [0.25, 0.93, 0.04, 0.04]
df['$e_i$'] = [0.0, -0.002, -0.09, 0.083]
df['$f_i$'] = [-0.4, 0.5, 0.02, 0.12]
df['$p_i$'] = [0.02, 0.84, 0.07, 0.07]
df['Porción generada'] = ['Tallo', 'Follaje cada vez más pequeño', 'Ramas izquierda', 'Ramas derecha']

df.round(3)


Out[19]:
$a_i$ $b_i$ $c_i$ $d_i$ $e_i$ $f_i$ $p_i$ Porción generada
$i$
0 0.000 0.000 0.000 0.25 0.000 -0.40 0.02 Tallo
1 0.950 0.005 -0.005 0.93 -0.002 0.50 0.84 Follaje cada vez más pequeño
2 0.035 -0.200 0.160 0.04 -0.090 0.02 0.07 Ramas izquierda
3 -0.040 0.200 0.160 0.04 0.083 0.12 0.07 Ramas derecha

La actividad consiste en generar el helecho mutante con los coeficientes de esta nueva tabla.

Hagan un nuevo archivo de jupyter (extensión .ipynb) con el nombre Tarea4_ApellidoNombre y subirlo en el enlace habilitad

3. Otra aplicación (elegible para proyecto)

Un paisaje fractal es una superficie generada usando un algoritmo estocástico diseñado para producir un comportamiento fractal que mimetiza la apariencia de un terreno natural. En otras palabras, el resultado de este procedimiento no es una superficie fractal determinística, sino una superficie aleatoria que exhibe comportamiento fractal.

Referencia:

Created with Jupyter by Esteban Jiménez Rodríguez.