Primeira vez aqui? Seja bem vindo e cheque o FAQ!
x

Como Gerar fractais (especificamente os chamados M-sets) a partir de números complexos ?

+1 voto
75 visitas

2 Respostas

+1 voto
respondida Jun 23 por MarcioGama (96 pontos)  

Vanderson, não entendi algumas coisas da sua resposta e enquanto tentava entender acabei fazer a minha própria implementação usando orientação a objetos.

Gostei de conhecer a biblioteca numba que acelera o processamento do código e a função linspace do numpy. O seu código também rodou muito mais rápido que o meu. (Por exemplo, o meu código com t = 50 e dividindo o intervalo \([-2, 1]\) e \([-1,1]\) em 100 partes demorou mais de 3 horas para rodar.) Porém não entendi como você usou os valores de \(c\) para determinar os pontos do \(M\) set.

Segue minha implementação:

import numpy as np
from numba import jit
import matplotlib.pyplot as plt

plt.figure(num=None, figsize=(7, 7), dpi=80, facecolor='w', edgecolor='k')
plt.axis([-2, 5 , -2, 5]);

class Mset(object):

    def __init__(self, t):
        self.t = t;

    @jit
    def calc(self):
        for i in np.linspace(-2,1, 100):
            for j in np.linspace(-1, 1, 100):
                x = 0;
                c = complex(i,j)
                for k in range(1,self.t):
                    x = x**2 + c;
                    if (abs(x) > 2):
                        plt.plot(c.real, c.imag, marker = 'o', color = 'red')
                        break;
                    plt.plot(c.real, c.imag, marker = 'o', color = 'k')

        plt.savefig('t100_100_50.png')


set = Mset(50);

set.calc()

Apresento também 3 resultados usando parâmetros diferentes (os dois primeiros rodaram bem rápido, porém o terceiro, como mencionado anteriormente, demorou mais de 3 horas)

usando t = 30 e dividindo os intervalos em 30 partes:

A imagem será apresentada aqui.

t= 50 e dividindo os intervalos em 40 partes:

A imagem será apresentada aqui.

t = 50 e dividindo os intervalos em 100 partes:

A imagem será apresentada aqui.

Devido ao tempo que demorou este último, desisti de rodar com os mesmos parâmetros que você (t= 100, e dividindo os intervalos em 200 partes).

0 votos
respondida Jun 16 por vanderson Delapedra (21 pontos)  
editado Jun 16 por vanderson Delapedra

Um número imaginário é dado pela existência de uma raiz quadrada de um número negativo, uma vez que, em termos reais, as raízes de números negativos seriam impossíveis de serem resolvidas. Desta forma, o número imaginário i é representado por √(-1).

Diante disso, os números complexos são obtidos pela adição de um número real e um número imaginário (a + bi) onde a e b são denominados números reais e i um número imaginário. O par acima é composto ainda por duas partes: uma real (a) e outra imaginária (bi), que permitem operações de adição e multiplicação a partir das seguintes regras:

(a+ib)+(c+id)=(a+c)+i(b+d)

(a+ib) X (c + id) = (ac - bd ) + i(ad+bc)

A regra de multiplicação nos permite verificar que a parte real bd é formada pela multiplicação de dois números imaginários i x i, uma vez que a raiz quadrada de um número imaginário (√(-1)^2 )) é igual a -1.

Além disso, se a parte imaginária é tida como zero, então tanto a multiplicação quanto a adição terão o padrão de números reais.

Verifica-se, portanto, que a aritmética dos números complexos contempla as premissas que a aritmética que os números reais consideram, sendo possível representar os números reais e complexos em um plano cartesiano complexo, tendo o eixo x representando os valores reais e o eixo y representando os números imaginários.

A imagem será apresentada aqui.

Uma vez que se identifica o plano de números reais juntamente com números imaginários, é possível verificar a exata localização de um número complexo.

Por exemplo, o número complexo (2+√(-4) ) pode ser representado por: 2+√((4) x (-1)), ou ainda, 2+√4 x √(-1), que por sua vez, se transforma em 2 + 2√(-1), ou 2+2i.

No plano complexo, esse número estaria localizado na seguinte posição

A imagem será apresentada aqui.

Dito isto, para encontrar o conjunto de mandelbrot, utiliza-se a função iterativa Zn=Z(n-1)^2+C (onde C representa um número complexo qualquer) para identificar quais números, dentro do plano complexo, não diverge para o infinito, ou seja, não cresce exponencialmente.

Especificando a equação, vale ressaltar que o número complexo C é dado como fixo, e se repete a cada iteração, conforme o exemplo abaixo, simbolizado por vermelho.
Por exemplo, se selecionarmos o ponto acima indicado, 2+2i, então teríamos os seguintes resultados:

Zn=Z(n-1)^2+C
Para Z0 = 0
Para Z1= 0^2+ (2+2i) = 2+ 2i
Para Z2 = 〖(2+2i)〗^2 +(2+ 2i) = 2 + 10 i
Para Z3 = 〖( 2 + 10i ) 〗^2 + (2+2i) = (-94 + 42i )
Para Z_4= 〖(-94 + 42i)〗^2 + (2+2i) = (7.074 + 6.944i)

Verifica-se, portanto, que o número complexo (2+ 2i) não estaria dentro do conjunto de mandelbrot, pois seu comportamento na função Zn=Z(n-1)^2+C é dado por um aumento exponencial, não convergindo para dentro de uma fronteira.

Diante disso, na medida em que as iterações são feitas, verifica-se que os numeros que não se dispersam para o infinito vão sendo concetrados em em regiões específicas, conforme os números subsequentes de iterações abaixo:

A imagem será apresentada aqui.

Benoit Mandelbrot foi o matemático francês de origem polonesa que primeiramente estudou a fundo a função Zn=Z(n-1)^2+C , utilizando mecanismos computacionais (FLAKE, 1998).

Números entre -2 e 1 não irão dispersar de forma exponencial. Números positivos menores do que 1 aumentarão, mas em tamanhos cada vez menores,tendendo à convergência.

Já em relação aos números negativos entre -2 e 0 as regras de multiplicação e elevação ao quadrado resultarem números positivos e de adição de um número negativo resultar em uma subtração, trabalham uma contra a outra, tornando os ganhos de adição cada vez menores a cada iteração.

Para representar essa estrutura na forma de programação orientada a objeto é preciso atribuir à classe os atributos específicos que envolverão o cálculo do mandelbrot set.
A primeira coisa a fazer é importação do pacote numpy, pacote básico da linguagem Python que nos permite trabalhar com matrizes de N dimensões.

A função @autojit do pacote Numba é utilizado para dar agilidade no cálculo, uma vez que inúmeras simulações são realizadas com infinitas soluções. Além disso, a biblioteca matplotlib.pyplot possibilita a plotagem do resultado.

import numpy
from numba import autojit
import matplotlib.pyplot as plt

Em seguida é necessário definir os argumentos da função “m-set”, neste caso foram são definidos três atributos, a saber: Re, Im e iter_max. Este último faz referência ao limite máximo de iterações (repetições).

Após a criação da função m-set, denominamos c e z, as variáveis que irão compor a função na sequência.

@autojit
def m-set  (Re, Im, inter_max):
        c = complex (Re, Im)
        z = 0

O método é definido a partir da função base do conjunto m-set, definindo um processo recursivo.

 for i in range (max_inter):
        z = z*z + c
        if (z.real*z.real + z.imag*z.imag) >= 4:
            return i
    return max_inter

Em seguida, após a definição de um array que armazena o resultado do teste em cada ponto do plano complexo(2.000 pontos para cada eixo).

Columns = 2000
Rows = 2000
Result = numpy.zeros([rows, columns])

O código dispõe de um looping que percorre o espaço real ( do intervalo -2 a 1)
E um outro looping, que percorre os 2.000 pontos da parte imaginária do ponto -1.0 a 1.0

for row_index, Re in enumerate(numpy.linspace(-2, 1, num=rows)):
for column_index, Im in enumerate (numpy.linspace(-1, 1, num=columns)):

A função m-set calcula, então, se o ponto definido dentro de cada looping pertence ou não ao conjunto de mandelbrot.

O resultado dessa função é estocado na array abaixo:

result[row_index, column_index] = mset(Re, Im, 100)

Onde 200 neste caso determina o número de iterações necessárias para que o ponto esteja dentro do conjunto. Sendo assim, na medida em que o número de iterações aumenta, a figura vai tomando forma gradativamente, conforme demonstrado anteriormente na figura 1.

result[row_index, column_index] = mset(Re, Im, 200)

Os resultados são plotados pelos comandos subsequentes, o 100 representa a dimensão da figura impressa na tela, o cmap representa o estilo da coloração da figura, interpolation o tipo de interpolação, e o plano onde a figura estará localizada.

plt.figure(dpi=100) , 
plt.imshow(result.T, cmap='hot', interpolation='bessel', extent=[-2, 1, -1, 1]), 

Assim, definindo abaixo os rótulos dos eixos, solicita-se a plotagem:

plt.xlabel('Real')
plt.ylabel('Imaginário')

plt.show()

O código completo é o que segue:

import numpy
from numba import autojit
import matplotlib.pyplot as plt

@autojit
def mset (Re, Im, max_inter):
        c = complex (Re, Im)
        z = 0

        for i in range (max_inter):
            z = z*z + c
            if (z.real*z.real + z.imag*z.imag) >= 4:
                return i
        return max_inter

#resolução da imagem
columns = 200
rows = 200
result = numpy.zeros([rows, columns])

for row_index, Re in enumerate(numpy.linspace(-2, 1, num=rows)):
    for column_index, Im in enumerate (numpy.linspace(-1, 1, num=columns)):
        result[row_index, column_index] = mset(Re, Im, 100)

plt.figure(dpi=100)
plt.imshow(result.T, cmap='hot', interpolation='bessel', extent=[-2, 1, -1, 1])
plt.xlabel('Real')
plt.ylabel('Imaginário')
plt.show()

Referência:

Flake, G. W. (1998). The Computational Beauty of Nature: Computer Explorations of Fractals, Chaos. Complex Systems, and Adaptation. MIT Press.

comentou Jun 16 por Pedro Henrique T (16 pontos)  
Olá, achei a resposta bem detalhada e a única coisa que eu vou sugerir aqui é a utilização do latex para deixar a apresentação das suas equações mais elegante. O link abaixo fornece dicas para a utilização dessa ferramenta aqui no prorum, já que alguns símbolos são diferentes do latex convencional.

http://prorum.com/index.php/213/como-escrever-equacoes-matematicas-usar-latex-no-prorum-com?show=213#q213
...