| área fractal | mutaciones |

El modelo "parser"

Antes de comenzar con la consabida parafernalia técnica, voy a constatar que, salvo algunas transformaciones de fórmulas conocidas, es muy difícil adelantar el aspecto de un fractal viendo sólo su fórmula. Sería como adivinar una melodía a partir de su gráfico de frecuencias de sonido. Por ello, es fácil que una fórmula muy trabajada sobre el papel, nos dé como resultado un bodrio (aunque, naturalmente, sobre gustos fractales no hay nada escrito). También es posible que una secuencia incongruente de operadores, fruto del bailoteo inconsciente de un orangután sobre tu teclado, genere una imagen espectacular, un nuevo tipo de fractal incluso, que te suponga la fama internacional y el colapso de tu buzón electrónico, repleto a rebosar de mensajes de fans incondicionales pidiéndote consejo. Como esto último es más que improbable, ya que la posesión de un orangután en el domicilio está penada por las leyes vigentes, es mejor seguir algunos pasos antes de que el descontrol se apodere de tu archivo de fórmulas.

Dicen por ahí, que cualquier fórmula fractal que se precie debe tener cierto margen de maniobrabilidad. Si aprovechamos al máximo las posibilidades que nos da Fractint en este sentido, e introducimos cuatro variables de función, podemos encontrarnos con más de ochocientas mil versiones distintas de una misma fórmula para probar, eso sin contar los diferentes valores de los parámetros, algoritmos de coloración, niveles de zoom, etc.. En esas ocasiones el tiempo se curva, hace bucles, y se producen situaciones absurdas, hasta que finalmente el incauto de turno entra en la UVI con la masa encefálica convertida en un fractal tipo Sierpinsky. Una vez más, amigos, aconsejo moderación.

Transformaciones clásicas

Partimos de una versión bastante sencilla del fractal de Mandelbrot. La perturbación de z supone un cambio bastante espectacular en la forma del conjunto. El test de salida, sin embargo, no cambia la forma del conjunto en sí, pero el exterior es claramente diferente.

Test real
real
Test imag.
imaginario
Test O
O lógico
Test Y
Y lógico

Pert. real
p1 = (1, 0)
Pert. real-imag.
p1 = (0.5, 0.5)
Pert. imag.
p1 = (0, 1)
Test módulo
módulo

Mandelbrot {
c = Pixel
z = p1 ; Perturbación de z.
:
z = z^2 + c
IF (real(p2) == 0) ; Módulo
  test = |z|<=imag(p2)
ELSEIF (real(p2) == 1) ; Real
  test = sqr(real(z))<=imag(p2))
ELSEIF (real(p2) == 2) ; Imaginario
  test = sqr(imag(z))<=imag(p2))
ELSEIF (real(p2) == 3) ; O lógico
  test = sqr(real(z))<=imag(p2) || sqr(imag(z))<=imag(p2)
ELSEIF (real(p2) == 4) ; Y lógico
  test = sqr(real(z))<=imag(p2) && sqr(imag(z))<=imag(p2)
ENDIF
test
}

¡Más tests de salida, por favor!

Hasta el momento estábamos trabajando con el conjunto de puntos cuya órbita no escapa de un círculo de radio determinado. ¿Por qué no de una corona circular determinada?:

Corona
p2 = (4, 0.09)

Mandel_ts1 {;
c = Pixel
z = p1
:
z = z^2 + c
|z|<=real(p2) && |z|>=imag(p2)
}

De un plumazo podemos añadir treinta nuevos argumentos de salida, a partir de una variable de función:

Arg. exp()
fn1 = exp()

Arg. sin()
fn1 = sin()

Mandel_ts2 {;
c = Pixel
z = p1
:
z = z^2 + c
abs(fn1(z)) <= imag(p2)
}

Claro que, pese a todo, esos test no dejan de ser algo estáticos. Para darles algo de movimiento incluiremos una variable que se incremente con cada iteración, y la utilizaremos en el test de salida:

Var. iter. 0.025
real(p2) = 0.025

Var. iter. 0.25
real(p2) = 0.25

Mandel_ts3 {;
c = Pixel, z = p1, iter = 0:
z = z^2 + c
iter = iter + 1
|z| <= real(p2)*iter + imag(p2)
}

A continuación veamos unos cuantos argumentos basados en el número e, lo cual no tiene ninguna justificación en especial:

exp(log())
real(p2) = 1
real(exp(log()))
real(p2) = 2

log(exp())
real(p2) = 0

Mandel_ts4 {;
c = Pixel
z = p1
:
z = z^2 + c
IF (real(p2) == 0)
  t = |log(exp(real(z)) + exp(imag(z)))|
ELSEIF (real(p2) == 1)
  t = |exp(log(abs(real(z))) * log(abs(imag(z))))|
ELSEIF (real(p2) == 2)
  t = real(exp(log(e+abs(real(z)))/log(e+abs(imag(z)))))
ENDIF
t <= imag(p2)
}

La mantisa, o parte decimal de un número, también nos ofrece un buen abanico de posibilidades:

Mant. (1, 1.25)
p2 = (1, 1.25)

Mant. (1, 0.8)
p2 = (1, 0.8)

Mant. (0, 0.8)
p2 = (0, 0.8)

Mandel_ts5 {;
c = Pixel
z = p1
:
z = z^2 + c
IF (real(p2) == 0)
  test = |z|-trunc(|z|) <= imag(p2)
ELSEIF (real(p2) == 1)
  test = |z - trunc(z)| <= imag(p2)
ENDIF
test
}

Modificando la sección de iteración

Algo ya muy trillado es poder modificar el exponente de z en la iteración, pero aquí añadimos la opción de que ese exponente cambie durante el proceso, dependiendo del número de iteraciones, la pendiente del punto, su módulo o el propio valor de z, modificado con una variable de función.

real(p2)+imag(p2)*cabs(c)
p2 = (1, 2)
p3 = (3, 4)
real(p2)+imag(p2)*cabs(cotan(z))
p2 = (2.2, 0.1)
p3 = (4, 4)
fn1 = cotan()

real(p2)+imag(p2)*iter
p2 = (1, 1)
p3 = (1, 4)
real(p2)+imag(p2)*imag(c)/real(c)
p2 = (1, 2)
p3 = (2, 4)

Mandel_si1 {;
c = Pixel
z = p1
iter = 0
:
IF (real(p3) == 0)
  z = z^real(p2) + c
ELSEIF (real(p3) == 1)
  z = z^(real(p2)+imag(p2)*iter) + c
ELSEIF (real(p3) == 2)
  z = z^(real(p2)+imag(p2)*imag(c)/real(c)) + c
ELSEIF (real(p3) == 3)
  z = z^(real(p2)+imag(p2)*cabs(c)) + c
ELSEIF (real(p3) == 4)
  z = z^(real(p2)+imag(p2)*cabs(fn1(z))) + c
ENDIF
iter = iter + 1
|z|<=real(p3)
}

Más retorcida es la siguiente fórmula, que concentra las posibilidades de variación en el parámetro c.

log-exp-ident
p1 = (0.1, 1)
p2 = (0.1, 4)
p3 = (2, 0)
fn1 = log()
fn2 = exp()
fn3 = ident()

tan-tan-ident
p1 = (-0.2, -0.2)
p2 = (12, 12)
p3 = (2, 0)
fn1 = tan()
fn2 = tan()
fn3 = ident()

sqrt-sqrt-ident
p1 = (4, 4)
p2 = (0.1, 0.1)
p3 = (2, 0)
fn1 = sqrt()
fn2 = sqrt()
fn3 = ident()

Mandel_si2 {;
cR = real(p1)*fn1(real(p2)*real(pixel))
cI = imag(p1)*fn2(imag(p2)*imag(pixel))
c = fn3(pixel + cR + flip(cI))
z = 0
:
z = z^2 + c
|z| <= real(p3)
}

Por el momento vamos a dejarlo aquí, pero hay más ejemplos en la galería de Mandelbrots.

| index | intro | software | galerías | misc |

· área fractal · sysifus, 12 de junio de 1999. ·