import pandas as pd
import numpy as np

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)

"""
Explanation: Fractales aleatorios
<img style="float: left; margin: 0px 0px 15px 15px;" src="https://upload.wikimedia.org/wikipedia/commons/f/fa/Fractal_Crown_of_morgoth2_5600x4200.jpg" width="400px" height="125px" />
<img style="float: right; margin: 0px 0px 15px 15px;" src="https://upload.wikimedia.org/wikipedia/commons/8/80/Super-volcano_Tierazon_fractal_Tiera4414.jpg" width="400px" height="125px" />
Referencias:
- http://fractalfoundation.org/resources/what-are-fractals/
- https://georgemdallas.wordpress.com/2014/05/02/what-are-fractals-and-why-should-i-care/
- https://en.wikipedia.org/wiki/Barnsley_fern
Antes que nada, ¿qué son fractales?

1. Fractales
<img style="float: right; margin: 0px 0px 15px 15px;" src="https://upload.wikimedia.org/wikipedia/commons/2/21/Mandel_zoom_00_mandelbrot_set.jpg" width="400px" height="125px" />


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.

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.

<img style="float: left; margin: 0px 0px 15px 15px;" src="https://upload.wikimedia.org/wikipedia/commons/thumb/4/4d/Fractal_canopy.svg/1200px-Fractal_canopy.svg.png" width="400px" height="125px" />

<img style="float: right; margin: 0px 0px 15px 15px;" src="https://upload.wikimedia.org/wikipedia/commons/e/ee/Sa-fern.jpg" width="400px" height="125px" />
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):
End of explanation
"""


# Importamos librerías
import matplotlib.pyplot as plt
import random

# Punto inicial
x, y = [0.0], [0.0]

# 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

# 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()

"""
Explanation: Con la anterior descripción, generemos el helecho de Barnsley con un código en python...
End of explanation
"""


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)

"""
Explanation: 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:
End of explanation
"""


