Até agora apenas vimos modelos onde os agentes têm regras de comportamento probabilísticas. Neste capítulo vamos ver modelos onde as regras de comportamento são deterministas, que usaremos para construir fractais geométricos. Para tal vamos aproveitar a capacidade que as tartarugas têm para desenhar trajectórias, como vimos no capítulo anterior, e introduziremos os botões de escolha múltipla.
Um fractal geométrico é um objecto que possui uma estrutura auto-semelhante em toda as escalas. Esta propriedade resulta do facto de serem construídos pela iteração ad infinitum da mesma regra de construção.
Muitas formas na natureza são aproximadas por esta geometria. No entanto, os fractais apresentados neste programa não foram inventados para simular as propriedades de padrões naturais, mas sim para mostrar que a matemática continha mais objectos para além das curvas e superfícies regulares da geometria tradicional.
Consideremos a curva do floco de neve. Começa-se com um segmento de recta, ao qual se chama iniciador, de seguida dividimo-lo em três segmentos iguais, depois substitui-se o terço do meio por um triângulo equilátero tirando-lhe a sua base. Neste momento completou-se a construção da unidade fundamental: –o gerador. A iteração deste processo consiste em aplicar a mesma regra a cada um dos segmentos de recta que resultam da iterada anterior, como ilustrado na figura. A curva do floco de neve é o objecto que se obtém no limite em que o número de iterações tende para infinito.
A auto-semelhança é o ingrediente do processo de construção, pois cada um dos quatro segmentos de recta contido na iterada k é a redução para 1/3 do comprimento do segmento de recta iniciador da iterada anterior. Consequentemente o objecto que resulta da passagem ao limite deste processo recursivo é exactamente auto-semelhante e é igual à ampliação de qualquer uma das suas partes.
O programa permite seleccionar a construção de diferentes fractais geométricos. Por exemplo, para gerar a árvore de Sierpinski, começa-se por escolher um ponto no plano e desenha-se três segmentos de recta desde esse ponto até aos vértices de um triângulo equilátero centrado no ponto inicial.
A iteração seguinte obtém-se aplicando a mesma operação aos vértices do triângulo considerados como novos pontos iniciais e tomando segmentos de recta com metade do comprimento dos da iteração anterior. A árvore de Sierpinski é o fractal que resulta da iteração sucessiva desta regra de construção.
Podemos ver este procedimento em acção seleccionando a árvore de Sierpinski no botão de escolha múltipla, cf. figura da direita, e pressionando sucessivamente o botão Desenhar uma iteracao. Pressionando este botão executa-se uma só vez a regra de construção do fractal seleccionado. O botão Desenhar ("forever button") executa sucessivamente o procedimento de Desenhar uma iteracao até que o utilizador o volte a pressionar.
A opção quadrado de Sierpinski utiliza uma regra similar a esta com outra simetria, como pode ser visto nas imagens seguintes. Neste caso colocamos o interruptor mostra-tartarugas em on para facilitar a compreensão da regra de construção do fractal.
Este fractal é construído recursivamente da seguinte forma: começa-se por escolher um ponto do plano e um certo comprimento l, depois, ao longo da vertical e da horizontal, desenha-se um segmento de recta entre 1/2 e 5/6 do comprimento inicial, de seguida coloca-se o ponto gerador da iteração seguinte à distância l do ponto inicial e faz-se a mesma coisa para as quatro direcções diagonais, só que neste caso o comprimento a considerar é l√2. A cada iteração o comprimento l é reduzido para 1/3 do comprimento anterior.
A escolha da opção tapete de Sierpinski fornece outra forma de construir o quadrado de Sierpinski. O processo de construção consiste em dividir o quadrado inicial em nove quadrados iguais, retirar o do meio e aplicar sucessivamente este procedimento aos quadrados que restam ao fim de cada iteração, conforme ilustrado nas imagens seguintes:
O utilizador pode modificar o aspecto visual do seu fractal escolhendo a cor da primeira turtle criada (cor-inicial). As turtles das gerações seguintes terão uma cor que corresponde à cor da sua progenitora incrementada de incremento (ver representação numérica das cores no capítulo 3). Desta forma o código de cores permite visualizar o resultado das sucessivas iterações da regra de construção.
O écran do computador tem um número finito de píxeis que correspondem à porção mínima (ponto) da imagem que pode se desenhada. Quando o comprimento a desenhar for inferior a 1 píxel, o programa informa-o desse facto e oferece-lhe a possibilidade de terminar a execução do programa (halt).
O leitor é agora convidado a experimentar estes fractais no seguinte applet:
Para correr este modelo no ambiente NetLogo, basta seguir o link fractais, se tiver instalado o software
O modelo está dividido nas seguintes secções:
iteracao | contém o número de iterações já decorridas |
comprimento | contém o comprimento a ser utilizado na iteração corrente |
cor | contém a cor definida na iteração anterior |
preparar | limpa e inicia as variáveis de acordo com o fractal pretendido, desenha a iteração 0 do fractal e cria uma turtle na posição especificada. |
desenhar | itera as regras de construção do fractal escolhido e actualiza as variáveis iteracao e cor. |
prepara-arvore-de-sierpinski | cria a iterada 0 da árvore de Sierpinski. |
prepara-floco-de-neve | cria a iterada 0 da curva do floco de neve. |
prepara-quadrado-de-sierpinski | cria a iterada 0 do quadrado de Sierpinski. |
prepara-tapete-de-sierpinski | cria a iterada 0 do tapete de Sierpinski. |
desenha-arvore-de-sierpinski | itera as regras de construção da árvore de Sierpinski. |
desenha-floco-de-neve | itera as regras de construção da curva do floco de neve. |
desenha-quadrado-de-sierpinski | itera as regras de construção do quadrado de Sierpinski. |
desenha-tapete-de-sierpinski | itera as regras de construção do tapete de Sierpinski. |
salta | move a turtle a distancia especificada sem que esta deixe rastro. |
muda-cor | altera a cor das turtles. |
calcula-factor | função necessária para saber quanto é que a turtle deve avançar em função da orientação (heading) desta. |
O código para gerar este programa é o seguinte. Este não é tão grande quanto parece, pois cada um dos quatro fractais tem regras de construção diferentes.
globals [ iteracao comprimento cor ] to preparar ca set iteracao 0 set cor cor-inicial cct 1 [ set size 10 set color cor-inicial if not mostra-tartarugas? [ ht ] ] if fractal = "arvore de Sierpinski" [ prepara-arvore-de-sierpinski ] if fractal = "floco de neve" [ prepara-floco-de-neve ] if fractal = "quadrado de Sierpinski" [ prepara-quadrado-de-sierpinski ] if fractal = "tapete de Sierpinski" [ prepara-tapete-de-sierpinski ] end to desenhar if comprimento < 1 [ user-message "Ultrapassou o limite de resolucao do ecran." ] if fractal = "arvore de Sierpinski" [ desenha-arvore-de-sierpinski ] if fractal = "floco de neve" [ desenha-floco-de-neve ] if fractal = "quadrado de Sierpinski" [ desenha-quadrado-de-sierpinski ] if fractal = "tapete de Sierpinski" [ desenha-tapete-de-sierpinski ] set iteracao iteracao + 1 muda-cor end to prepara-arvore-de-sierpinski ask turtles [ setxy 0 -70 pd ] set comprimento 140 end to desenha-arvore-de-sierpinski locals [ angulo ] ask turtles [ set angulo 0 hatch 3 [ set heading angulo fd comprimento set angulo angulo + 120 ] die ] set comprimento comprimento / 2 end to prepara-floco-de-neve set comprimento 420 ask turtles [ setxy -121 -210 pd repeat 3 [ hatch 1 [] fd comprimento rt 120 ] die ] set comprimento comprimento / 3 end to desenha-floco-de-neve ask turtles [ repeat 2 [ hatch 1 [] fd comprimento lt 60 hatch 1 [] fd comprimento rt 120 ] die ] set comprimento comprimento / 3 end to prepara-quadrado-de-sierpinski ask turtles [ setxy 0 0 pd ] set comprimento 128 end to desenha-quadrado-de-sierpinski locals [ angulo ] ask turtles [ set angulo 0 hatch 8 [ set heading angulo salta (comprimento / 2) * calcula-factor heading fd (comprimento / 3 ) * calcula-factor heading salta (comprimento / 6) * calcula-factor heading set angulo angulo + 45 ] die ] set comprimento comprimento / 3 end to prepara-tapete-de-sierpinski set comprimento 243 ask patches with [ abs pxcor <= 121 and abs pycor <= 121 ][ set pcolor blue ] set comprimento comprimento / 3 end to desenha-tapete-de-sierpinski locals [ lado angulo x y ] set lado (comprimento - 1) / 2 ask turtles [ without-interruption [ set angulo 0 set x xcor set y ycor hatch 8 [ set heading angulo fd comprimento * calcula-factor angulo setxy round xcor round ycor set angulo angulo + 45 ] ask patches in-radius (ceiling (lado * sqrt 2)) [ if abs (pxcor - x) <= lado and abs (pycor - y) <= lado [ set pcolor black ] ] die ] ] set comprimento comprimento / 3 end to salta [ distancia ] pu fd distancia pd end to muda-cor set cor cor + incremento if cor = black [ set cor cor + incremento ] ask turtles [ set color cor ] end to-report calcula-factor [ angulo ] ifelse (angulo / 45) mod 2 = 0 [ report 1 ][ report sqrt 2 ] end
Vejamos em detalhe os conceitos que são novos:
to preparar ca set iteracao 0 set cor cor-inicial cct 1 [ set size 10 set color cor-inicial if not mostra-tartarugas? [ ht ] ] if fractal = "arvore de Sierpinski" [ prepara-arvore-de-sierpinski ] if fractal = "floco de neve" [ prepara-floco-de-neve ] if fractal = "quadrado de Sierpinski" [ prepara-quadrado-de-sierpinski ] if fractal = "tapete de Sierpinski" [ prepara-tapete-de-sierpinski ] end
A rotina preparar tem o objectivo de gerar a iterada 0 do fractal escolhido, para tal limpa o écran e devolve às variáveis os seus valores iniciais.
O comando if not mostra-tartarugas? [ ht ] esconde as tartarugas criadas se a variável mostra-tartarugas definida no interruptor com o mesmo nome for false. O comando ht (hide-turtle) é equivalente a atribuir o valor true à variável hidden? da turtle correspondente. Tal implica que todas as suas descendentes (instrução hatch) herdarão esta característica.
A variável fractal é definida no botão de escolha múltipla com o mesmo nome e consoante o seu valor a rotina preparar chama a rotina auxiliar que prepara o fractal correspondente.
Para criarmos um botão de escolha múltipla clicamos em e em seguida na área de trabalho. Esta acção abrirá a caixa de diálogo Chooser como pode ser vista na figura:
nesta caixa especificamos quais são os valores possíveis para a variável fractal. Os valores das variáveis definidas por botões de escolha múltipla têm de ser números ou strings, no segundo caso têm de começar e de acabar com o símbolo ".
to desenhar if comprimento < 1 [ user-message "Ultrapassou o limite de resolucao do ecran." ] if fractal = "arvore de Sierpinski" [ desenha-arvore-de-sierpinski ] if fractal = "floco de neve" [ desenha-floco-de-neve ] if fractal = "quadrado de Sierpinski" [ desenha-quadrado-de-sierpinski ] if fractal = "tapete de Sierpinski" [ desenha-tapete-de-sierpinski ] set iteracao iteracao + 1 muda-cor end
A rotina desenhar parte da iterada 0 do fractal escolhido e aplica-lhe as regras de construção especificadas na rotina auxiliar correspondente.
O comando if comprimento < 1 [ user-message "Ultrapassou o limite de resolucao do ecran." ] abre uma caixa de dialogo (pop up) que mostra a mensagem "Ultrapassou o limite de resolucao do ecran.", quando a variável comprimento for inferior a 1 píxel.
to prepara-arvore-de-sierpinski ask turtles [ setxy 0 -70 ask patch-here [ set pcolor cor ] pd ] set comprimento 140 end
A rotina prepara-arvore-de-sierpinski cria a iterada 0 do fractal árvore de Sierpinski e inicia a variável comprimento.
O comando ask patch-here [ set pcolor cor ] muda a cor do patch sobre o qual a turtle se encontra para a cor especificada.
to desenha-arvore-de-sierpinski locals [ angulo ] ask turtles [ set angulo 0 hatch 3 [ set heading angulo fd comprimento set angulo angulo + 120 ] die ] set comprimento comprimento / 2 end
A rotina desenha-arvore-de-sierpinski itera as regras de construção do fractal árvore de Sierpinski e actualiza a variável comprimento.
A declaração locals [ angulo ] indica a existência de uma variável local, o angulo, que vai ser posteriormente atribuído à orientação (heading) de cada turtle.
O comando hatch numero [ comandos ] funciona como um ciclo, i.e. cria uma turtle, executa a lista de comandos e repete o procedimento até que não hajam mais turtles para criar. Graças a este comportamento podemos fazer com que a orientação (heading) de cada "cria" rode de 120° para a direita relativamente à "cria" que foi criada antes com os comandos:
set heading angulo set angulo angulo + 120
e ordenar que esta avance comprimento com o comando fd comprimento.
O comando die não mata todas as turtles, apenas mata as "progenitoras" pois o NetLogo "protege" as "crias", as quais só ficam activas na iteração seguinte. Por essa razão, neste caso, não precisamos de usar a instrução without-interruption. Para o NetLogo "próxima iteração" significa a próxima instrução ask, pelo que se estivéssemos a usar o seguinte código:
ask ConjuntoDeAgentes1 [ comandos1 hatch numero [ comandos2 ] ask ConjuntoDeAgentes2 [ comandos3 ] die ]
todos os agentes de ConjuntoDeAgentes1 morreriam, pelo que neste caso precisaríamos de usar a instrução without-interruption para que só morressem os "progenitores", como podemos ver no caso do tapete de Sierpinski.
to prepara-floco-de-neve set comprimento 420 ask turtles [ setxy -121 -210 pd repeat 3 [ hatch 1 [] fd comprimento rt 120 ] die ] set comprimento comprimento / 3 end
A rotina prepara-floco-de-neve cria a iterada 0 do fractal floco de neve e inicia a variável comprimento.
Para gerar a iteração 0 a turtle 0 gera a cria 1, avança até à posição 2, roda 120° e gera a cria 2, depois avança até à posição 3, roda 120° e gera a cria 3, por fim avança até à posição 1 e morre, conforme esquematizado na figura da direita. Estas instruções estão condensadas no seguinte código:
repeat 3 [ hatch 1 [] fd comprimento rt 120 ] die
to desenha-floco-de-neve ask turtles [ repeat 2 [ hatch 1 [] fd comprimento lt 60 hatch 1 [] fd comprimento rt 120 ] die ] set comprimento comprimento / 3 end
A rotina desenha-floco-de-neve itera as regras de construção do fractal floco de neve e actualiza a variável comprimento.
Para gerar a iterada seguinte, a turtle 0 gera a cria 1, avança 1/3 do comprimento, roda para a esquerda 60°, gera a cria 2, avança 1/3 do comprimento, roda para a direita 120° gera a cria 3, avança 1/3 do comprimento, roda para a esquerda 60°, gera a cria 4 e morre, conforme esquematizado nas imagens seguintes:
Estas instruções estão condensadas no seguinte código:
repeat 2 [ hatch 1 [] fd comprimento lt 60 hatch 1 [] fd comprimento rt 120 ] die
to prepara-quadrado-de-sierpinski ask turtles [ setxy 0 0 pd ] set comprimento 128 end
A rotina prepara-quadrado-de-sierpinski cria a iterada 0 do fractal quadrado de Sierpinski e inicia a variável comprimento.
to desenha-quadrado-de-sierpinski locals [ angulo ] ask turtles [ set angulo 0 hatch 8 [ set heading angulo salta (comprimento / 2) * calcula-factor heading fd (comprimento / 3 ) * calcula-factor heading salta (comprimento / 6) * calcula-factor heading set angulo angulo + 45 ] die ] set comprimento comprimento / 3 end
A rotina desenha-quadrado-de-sierpinski itera as regras de construção do fractal quadrado de Sierpinski e actualiza a variável comprimento.
O caso do quadrado de Sierpinski é semelhante ao caso da árvore de Sierpinski, só que neste caso temos 8 turtles que avançam ao longo das direcções dos eixos coordenados, ou ao longo das direcções das diagonais, i.e. cada cria roda 45° relativamente à cria anterior. Por essa razão temos as instruções:
set heading angulo set angulo angulo + 45
Designando por l o valor da variável comprimento, as crias que estão orientadas segundo os eixos saltam l/2, avançam l/3 e saltam l/6, enquanto que as crias orientadas segundo as diagonais saltam l√2/2, avançam l√2/3 e saltam l√2/6. Para simplificar o código usamos a função calcula-factor, a qual fornece o valor 1 ou √2, consoante a cria esteja orientada segundo os eixos ou segundo as direcções diagonais. Em consequência de tal as regras de movimento das turtles ficam condensadas nas três seguintes instruções:
salta (comprimento / 2) * calcula-factor heading fd (comprimento / 3 ) * calcula-factor heading salta (comprimento / 6) * calcula-factor heading
to prepara-tapete-de-sierpinski set comprimento 243 ask patches with [ abs pxcor <= 121 and abs pycor <= 121 ][ set pcolor blue ] set comprimento comprimento / 3 end
A rotina prepara-tapete-de-sierpinski cria a iterada 0 do fractal tapete de Sierpinski e inicia a variável comprimento.
A iterada 0 consiste em desenhar um quadrado azul de lado comprimento centrado na origem e em criar uma turtle na origem, conforme esquematizado na figura da direita.
to desenha-tapete-de-sierpinski locals [ lado angulo x y ] set lado (comprimento - 1) / 2 ask turtles [ without-interruption [ set angulo 0 set x xcor set y ycor hatch 8 [ set heading angulo fd comprimento * calcula-factor angulo setxy round xcor round ycor set angulo angulo + 45 ] ask patches in-radius (ceiling (lado * sqrt 2)) [ if abs (pxcor - x) <= lado and abs (pycor - y) <= lado [ set pcolor black ] ] die ] ] set comprimento comprimento / 3 end
A rotina desenha-tapete-de-sierpinski itera as regras de construção do fractal tapete de Sierpinski e actualiza a variável comprimento.
Para gerar a iterada seguinte a turtle 0 divide o quadrado onde se encontra em nove quadrados iguais e pinta de preto aquele onde se encontra. Cf. imagens seguintes.
Tal é feito usando os seguintes comandos:
ask patches in-radius (ceiling (lado * sqrt 2)) [ if abs (pxcor - x) <= lado and abs (pycor - y) <= lado [ set pcolor black ] ]
A variável lado designa a distância do centro do quadrado a um dos seus lados, logo lado = (comprimento - 1 )/ 2.
Poderíamos ter usado o seguinte comando
ask patches with [ abs (pxcor - x) <= lado and abs (pycor - y) <= lado ][ set pcolor black ]
para realizar a mesma tarefa, porém este comando é muito menos eficiente em termos computacionais quando os quadrados são pequenos, pois a condição abs (pxcor - x) <= lado and abs (pycor - y) <= lado é verificada para todos os patches e não apenas para aqueles que estão dentro do menor círculo que contem o quadrado.
De seguida cria oito descendentes, envia-os para o centro dos oito quadrados adjacentes e morre. Usando-se para tal os seguintes comandos:
hatch 8 [ set heading angulo fd comprimento * calcula-factor angulo setxy round xcor round ycor set angulo angulo + 45 ]
O comando setxy round xcor round ycor atribui a cada turtle as coordenadas do patch onde se encontra.