segunda-feira, 29 de novembro de 2010

Explorações fractais V

Depois de experimentar algumas pequenas alterações no Mandelbrot, resolvi colocar a CPU a trabalhar de verdade. Experimentei mudar a recursão para z=z200+c e o resultado foi melhor que o esperado.

As imagens mostram ampliações sucessivas do Mandelbrot modificado.

Explorações fractais IV

O fractal original de Mandelbrot usa a recursão z=z2+c, mas outras potências são igualmente interessantes. Resolvi desenhar uma seqüência (de 2 a 13), para compará-los.

O zoom no de potência 6 mostra detalhes novos.


Clique nas imagens para vê-las no tamanho original.

sexta-feira, 12 de novembro de 2010

Democracia evolutiva

A maior polêmica das últimas eleições (apesar dos esforços de Dilma e Serra), foi a do palhaço Tiririca. Gastou-se muito papel de jornal para o que será apenas um dentre 513 deputados federais. Tenho certeza que há muitos outros deputados ainda mais interessantes.

A indignação, creio, não foi proporcional ao tamanho do problema, se é que existe um. Não está sequer provado que Tiririca será um mau deputado, analfabeto ou não. Pode ser que um analfabeto dê mais valor à educação que os doutores que normalmente habitam o planalto central.

As pessoas acreditam ter o discernimento necessário para saber qual o melhor candidato, mesmo quando sequer lembram em quem votaram nas eleições anteriores! Além disso, como não existe um sistema de avaliação, não há como decidir, ao fim do mandato, se um deputado fez um bom trabalho. E os jornais dedicam mais tempo às aberrações que ao trabalho sendo conduzido seriamente. As escolhas para o legislativo acabam sendo, em grande parte, ideológicas ou de protesto (como parece ser o caso do Tiririca).

Por isso, sugiro algumas mudanças no sistema eleitoral (relativas ao legislativo, somente). Em primeiro lugar, o voto não deveria ser obrigatório. Assim, evitamos os votos de protesto e economizamos uns reais. Admito não ter nenhuma prova de que os revoltados não sairiam para votar mesmo assim, nem de que o voto de protesto tenha conseqüências nefastas para a nação. De qualquer forma, ele parece incomodar as pessoas e ocupar demasiado espaço nos jornais. Em segundo lugar, supondo que apenas as pessoas que se consideram politizadas (o que não significa que são) compareçam para votar, deveríamos ter um pouco mais de aleatoriedade nas eleições. Por exemplo, 10% das cadeiras do Congresso Nacional poderiam ser sorteadas. Aceitando que não sabemos sempre fazer as melhores escolhas, inserir um fator de aleatoriedade nos ajudará a enxergar possibilidades que normalmente não consideraríamos.

O sorteio não é uma novidade na democracia. Os gregos o usavam para selecionar todos os cargos, exceto o de general. Eles temiam que os cidadãos mais ricos ou conhecidos dominassem as eleições. Outra instituição daqueles tempos que poderíamos reviver é a do ostracismo. Os eleitores podiam, uma vez por ano, anotar o nome de qualquer cidadão e enviar o mais votado para o exílio por dez anos. A cada eleição, poderíamos também eleger alguns deputados para o ostracismo; assim os mais desprezados ganhariam um descanso por alguns anos (e nós deles).

Acredito que essas alterações seriam muito mais úteis e educativas que o voto obrigatório. Agregar um elemento de aleatoriedade tiraria o peso da necessidade de controle que os eleitores com inclinações menos democráticas ainda exibem e também permitiria à sociedade analisar seus próprios preconceitos. O voto pelo ostracismo seria um mecanismo mais construtivo de manifestação de instatisfação que o voto de protesto.

Pior do que está, garanto, não fica.

segunda-feira, 8 de novembro de 2010

Explorações fractais III

As imagens geradas pelo algoritmo inicial tinham faixas de cores, porque ele usa o número de passos necessários para a função z=z2+c fugir para o infinito.

A ação toda dá-se na função mandel().


function mandel(x,y) {
var c=0;
var r=0;
var i=0;
var MAXITER=1000;
while(r*r+i*i<4 && c<MAXITER) {
var nr=r*r-i*i+x;
var ni=2*r*i+y;
r=nr;
i=ni;
c+=1;
}
return c;
}



Cada coordenada da tela (x,y) vira um número imaginário (r,i). A função tira o quadrado desse número e soma o valor inicial até que o resultado seja maior que 4 (a conta tendeu ao infinito) ou o número de iterações passou de 10.000 (indicando que ele não vai tender ao infinito).

O número de iterações (c) é usado para escolher a cor e como muitos pontos caem entre uma iteração e outra, as faixas acabam aparendo.

Uma solução simples que encontrei para eliminar as faixas é normalizar com o MAXITER. A figura abaixo mostra o resultado.



A única mudança necessária no código é trocar o último comando da função mandel():


return (c/MAXITER)*256;



Uma alternativa é apresentada na Wikipédia: Continuous Smooth Coloring. O código e a imagem abaixo mostram a diferença. A imagem, ademais, foi gerada com uma paleta um pouco diferente (os componentes verde e vermelho são iguais).


return c + 1 - Math.log(Math.log(r*r+i*i))/Math.log(2);




Para terminar, como bônus, uma alteração descoberta por acaso que parece criar camadas na imagem.


return (Math.log(c)/Math.log(MAXITER))*256;


quarta-feira, 3 de novembro de 2010

Explorações fractais II

Como o primeiro explorador não guardava a seqüência de passos para encontrar um ponto específico do Mandelbrot, resolvi fazer umas pequenas alterações. Agora, cada zoom é desenhado num Canvas novo.


<html>
<head>
<style>canvas {border:2px solid black; margin: 1px};</style>
</head>
<body>
<script>
function mandel(x,y) {
var c=0;
var r=0;
var i=0;
var MAXITER=1000;
while(r*r+i*i<4 && c<MAXITER) {
var nr=r*r-i*i+x;
var ni=2*r*i+y;
r=nr;
i=ni;
c+=1;
}
return c;
}

var body=document.getElementsByTagName("body")[0];
var canvas, ctx, imageData;
var minx=-2;
var miny=-2;
var maxx=2;
var maxy=2;

function prepare() {
if(canvas) {
canvas.onclick=null;
}
canvas=document.createElement("CANVAS");
canvas.setAttribute("width", 256);
canvas.setAttribute("height", 256);
body.appendChild(canvas);
ctx=canvas.getContext("2d");
imageData=ctx.getImageData(0,0,256,256);
canvas.onclick=zoom;
}

function plot() {
var deltax=(maxx-minx)/256;
var deltay=(maxy-miny)/256;
var deltay=(maxy-miny)/256;

prepare();
for(var x=0; x<256; x++) {
for(var y=0; y<256; y++) {
var c=mandel(minx+x*deltax, miny+y*deltay);
var red=(c*8)%255;
var green=(c*9)%255;
var blue=(255-c*4)%255;
var index=(x+y*imageData.width)*4;
imageData.data[index+0]=red;
imageData.data[index+1]=green;
imageData.data[index+2]=blue;
imageData.data[index+3]=0xff;
}
}
ctx.putImageData(imageData,0,0);
}
plot();

function zoom(e) {
var x=minx+(maxx-minx)*((e.clientX-canvas.offsetLeft)/256);
var y=miny+(maxy-miny)*((e.clientY-canvas.offsetTop)/256);
var dx=(maxx-minx)/4;
var dy=(maxy-miny)/4;

minx=x-dx;
maxx=x+dx;
miny=y-dy;
maxy=y+dy;
plot();
}
</script>
</body>
</html>

O resultado é o que se vê na figura abaixo.


Clique na imagem para vê-la no tamanho original.

Explorações fractais

Resolvi investigar o novo elemento Canvas do HTML5. Tenho visto alguns efeitos interessantes e estava na hora de aprender a usá-lo. Tendo em vista a recente partida do Mandelbrot, resolvi criar uns fractais em sua homenagem.

Com poucas linhas, consegui criar um navegador de Mandelbrot. Basta clicar num ponto, que o programa amplia a região em volta dele. Para voltar ao início, basta recarregar a página.

O código abaixo funciona no Firefox. Não o testei em outros navegadores, exceto pelo IE8, no qual ele não funciona.


<html>
<head>
</head>
<body>
<canvas id="canvas" width="256" height="256"></canvas>
<script>

function mandel(x,y) {
var c=0;
var r=0;
var i=0;
var MAXITER=1000;
while(r*r+i*i<4 && c<MAXITER) {
var nr=r*r-i*i+x;
var ni=2*r*i+y;
r=nr;
i=ni;
c+=1;
}
return c;
}

var canvas=document.getElementById("canvas");
var ctx=canvas.getContext("2d");
var imageData=ctx.getImageData(0,0,256,256);

var minx=-2;
var miny=-2;
var maxx=2
var maxy=2;


function plot() {
var deltax=(maxx-minx)/256;
var deltay=(maxy-miny)/256;

for(var x=0; x<256; x++) {
for(var y=0; y<256; y++) {
var c=mandel(minx+x*deltax, miny+y*deltay);
var red=(c*8)%255;
var green=(c*9)%255;
var blue=(255-c*4)%255;
var index=(x+y*imageData.width)*4;
imageData.data[index+0]=red;
imageData.data[index+1]=green;
imageData.data[index+2]=blue;
imageData.data[index+3]=0xff;
}
}
ctx.putImageData(imageData,0,0);
}
plot();

function zoom(e) {
var x=minx+(maxx-minx)*((e.clientX-canvas.offsetLeft)/256);
var y=miny+(maxy-miny)*((e.clientY-canvas.offsetTop)/256);
var dx=(maxx-minx)/4;
var dy=(maxy-miny)/4;

minx=x-dx;
maxx=x+dx;
miny=y-dy;
maxy=y+dy;
plot();
}
canvas.onclick=zoom;

</script>
</body>
</html>

Não é muito código para o que o programa faz. Percebi que o navegador vai se tornar uma plataforma interessante para a criação de jogos.



O número máximo de iterações está fixo em 1000. No início, 64 são suficientes, mas com zoom muito grande mesmo 1000 são poucas. Então, é preciso achar uma maneira de ir aumentando aos poucos o número de iterações. Deixo isso como exercício para o leitor.