sexta-feira, 9 de outubro de 2009

Problema 2.17

Qual a Distância de Hamming entre duas cadeias de caracteres, isto é, em quantas posições divergem? Se as cadeias tiveram o mesmo comprimento é fáciul:


def hamming_b(cad1,cad2): # Começar com esta solução...
"""
Determina a distância de Hamming entre duas cadeias.
Para o mesmo tamanho!!!
"""
conta = 0
for i in range(len(cad1)):
if cad1[i] != cad2[i]: # erro corrigido!
conta = conta + 1
return conta

Limitamo-nos a usar o padrão acumulador, percorrendo as cadeias posição a posição e testando a igualdade (linha 8). Mas, e se tiverem comprimento diferente? Bom ,só é preciso um pequeno ajuste.


def hamming_a(cad1,cad2):
"""
Determina a distância de Hamming entre duas cadeias.
"""
conta = 0
comp_min = min(len(cad1),len(cad2))
comp_max = max(len(cad1),len(cad2))
for i in range(comp_min):
if cad1[i] != cad2[i]:
conta = conta + 1
conta = conta + (comp_max - comp_min)
return conta


Testamos as sub-cadeias de igual comprimento, como anteriormente, e depois consideramos que os caracteres em excesso devem todos ser contabilizados para a distância de Hamming.

Problema 2.16

Pretende-se um programa que determine se uma dada cadeia de caracteres é, ou não, uma capicua. São capicuas as cadeias que são idênticas lidas da esquerda para a direita, e da direita para a esquerda. Exemplo: madam.


def capicua_a(cad):
"""
Determina se a cadeia é uma capicua.
"""
cap_p = True
while cap_p and (len(cad) >= 2):
cap_p = cap_p and (cad[0] == cad[-1])
cad = cad[1:-1]
return cap_p


Qual a lógica do programa? Comparar os caracteres a igual distância das extremidades (linha 7) e determinar se o resultado é verdadeiro ou falso. Se for falso, cap_p, que no início é True, passa a False provocando o abandono do ciclo while (linha 6). Se o cilco while terminar porque foram analisados todos os pares caracteres então cap_p será True (nunca é alterada) e esse valor é devolvido (linha 9). A variável cap_p funciona como uma bandeira que sinaliza uma condição(flag).

Problema 2.13

Pretende-se um programa que dada uma cadeia de caracteres substitua todas as ocorrências de vogais por espaços em branco.


import string
def retira_vogais(cad):
"""
Retira as vogais numa cadeia, substituindo-as por espaços em branco.
"""
vogais = 'aeiou'
for ch in vogais:
cad = string.replace(cad,ch,' ')
return cad

Programa que usa o método definido para cadeias replace. A estratégia é simples: um ciclo em que ch vai sendo sucessivamente associado a uma vogal. Em cada passagem pelo ciclo for são retiradas as ocorrências da vogal (linha 8).

Coisas práticas: instalar novos módulos

A linguagem Python pode crescer de acordo com os nossos desejos. Precisamos apenas acrescentar novos módulos. Para isso é preciso obter e instalar os módulos. Para saber onde os obter podemos googlar usando python como palavras chave, ou dar um passeio pelos sítios habituais de python de que http://www.python.org é sempre o primeiro a considerar. Devemos, finalmente, ter sempre em atenção qual a versão de python instalada, e escolher a versão do módulo compatível com essa versão e com a versão do sistema operativo (Windows, Mac OS ou Linix) ! Quando arranca com o python, directamente ou via um ambiente integrado de desenvolvimento, ele dá a informação sobre a versão instalada.


Agora os módulos. Se existir um instalador do módulo para o seu sistema operativo e para a versão de python instalada, use-o e não se preocupe mais. Se não existir e tiver apenas o ficheiro .py deve colocar o módulo na pasta site-packages localizada em:



Windows: C:\Python26\Lib\site-packages


Linux: /usr/local/lib/python2.6/site-packages


Mac OS X (versão pré-instalada 2.5): /usr/local/lib/python2.5/site-packages

Mac OS X (versão instalada por si): /Library/Frameworks/Python.framework/Versions/2.6/lib/python2.6/site-packages


As coisas podem ser um pouco mais complexas, caso o módulo não tenha instalador e a distribuição da fonte tenha sido feito usando o distutils. Neste caso o módulo vem comprimido, com mais outros ficheiros. Deve descomprimir o módulo com o aplicativo/comando adequado. É, em geral, criada uma pasta com o nome do módulo seguido da versão do módulo. Lá dentro encontrará, entre outras coisas, um ficheiro README que contém as instruções de instalação, que deve seguir. Normalmente resume-se a abrir uma janela de terminal/consola, mudar-se para a directoria onde está o módulo com um comando cd e emitir o comando python setup.py install.

Pode obter informações mais detalhadas, incluindo variantes à instalação básica, aqui

quinta-feira, 8 de outubro de 2009

Pi: ver para crer!

No post anterior mostrei como se pode calcular o valor de Pi usando o Método de Monte Carlo. Também já falei no módulo cTurtle que permite colocar tartarugas a fazer desenhos numa tela. Vamos juntar as duas coisas e fornecer uma solução ao cálculo do vaslor de Pi com animação! Para já o código.


import random
import math
import cTurtle


def monte_carlo_animado(num_dardos):
"""
Valor de pi pelo método de monte Carlo.
Versão gráfica.
"""
# prepara a visualização
janela = cTurtle.Turtle()
janela.setWorldCoordinates(-2,-2,2,2)
janela.hideturtle()

janela.up()
janela.goto(-1,0)
janela.down()
janela.goto(1,0)

janela.up()
janela.goto(0,1)
janela.down()
janela.goto(0,-1)

# vamos aos cálculos
conta_dardos_in = 0
janela.up()

for i in range(num_dardos):
x = random.random()
y = random.random()

d = math.sqrt(x**2 + y**2)
janela.goto(x,y)

if d <= 1:
conta_dardos_in = conta_dardos_in + 1
janela.color("blue")
else:
janela.color("red")

janela.dot()

janela.exitOnClick()

res = 4 * (conta_dardos_in / float(num_dardos))

return res


if __name__ == '__main__':
print monte_carlo_animado(1500)


A parte da cálculo propriamente dito já foi explicado. Tratemos pois à animação. As linhas 11,12 e 13 criam a tartaruga e definem a dimensão da tela. Das linhas 15 à 22 desenhamos os eixos. Na linha 33 colocamos a tartaruga no sítio certo.Os dardos dentro do círculo serão azuis (linha 37) e ou outros vermelhos (linha 39). São desenhados como pontos (linha 41). Se clicarmos dentro da tela o programa termina (linha 43). Executando o programa para 1500 dardos obtemos a linda figura:


.

Pi revisitado

Já aqui falámos do número Pi, um número irracional que só pode ser calculado por aproximação. Existe um método interessante baseado em ideias probabilísticas. Por essa razão, essas técnicas são conhecidas pelo nome genérico de Método de Monte Carlo. Em que consiste? Suponhamos uma circunferência de raio 1 inscrita num quadrado de lado 2 como mostra a figura.





Sabemos que a área é dada por:


\pi \times R^2


Com o raio R igual a um então a área da circunferência é igual a Pi. Fixemo-nos agora no canto superior direito da figura.





Claramente a área do quarto de círculo é igual à quarta parte de Pi. É aqui que entra o nosso método. Admitamos que a figura acima está afixada numa parede e que nós atiramos dardos em sua direcção. Admitamos também, que todos os dardos acertam na figura e que todos os pontos do quadrado têm a mesma probabilidade de serem atingidos (tecnicamente dizemos que estamos a extrair os pontos de uma distribuição uniforme). Então, ao fim de muitos dardos disparados o número de dardos que caem dentro do quarto de círculo é proporcional à área, ou seja, a Pi/4.

Com base nesta ideia tão simples chegamos ao programa seguinte:




import math
import random

def monte_carlo_pi(num_dardos):
"""
Calcula o valor de pi pelo método de monte Carlo.
"""
# define e inicializa acumulador
conta_dardos_in = 0.0
for i in range(num_dardos):
# gera posição dardo i
x= random.random()
y= random.random()
# calcula distância à origem
d = math.sqrt(x**2 + y**2)
if d <= 1:
conta_dardos_in = conta_dardos_in + 1
res_pi = 4 * (conta_dardos_in/float(num_dardos))
return res_pi




Analisemos o código. Nas linhas 1 e 2 importamos os módulos math e random. O primeiro porque vamos precisar de calcular uma raiz quadrada, o segundo, porque precisamos gerar as coordenadas onde os dardos vão chegar. Em relação ao programa em si saliente-se que temos de resolver duas questões. A primeira, consiste em saber como geramos as coordenadas do dardo; a segunda, liga-se à questão da contagem do número de dardos que caem dentro do círculo. Para a primeira questão, usamos um gerador de números aleatórios que nos fornece números reais no intervalo [0,1] (linhas 12 e 13). Para a segunda questão, basta pensar que, dada a construção (o raio vale 1), todos os pontos a uma distância da origem menor ou igual a 1 caem sobre ou no interior da zona de interesse. A distância (euclidiana) à origem é calculada na linha 15. Na linha 17 contamos os que acertam no quarto de círculo. No final basta multiplicar a percentagem dos que caem dentro por quatro para obter o valor aproximado de Pi (linha 18). Uma nota final para referir que usámos o padrão de programação conhecido por acumulador: neste caso o nome conta_dardos cumpre o papel de contador, com as duas fases de inicialização (linha 9) e actualização (linha 17).

Testemos o programa.


>>> monte_carlo_pi(1000)
3.096
>>> monte_carlo_pi(100000)
3.13612
>>>


Não está mal!

segunda-feira, 5 de outubro de 2009

Espirais

Num post recente falei do módulo cTurtle. De um modo simples era possível desenhar polígonos regulares. Mais um exemplo, muito simples, para desenhar espirais.

Vou construir a dita de modo aproximado recorrendo a segmentos de recta que vão rodando. Neste caso é evidente que precisamos definir várias coisas:
- o comprimento do segmento inicial
- o comprimento do segmento final
- o ângulo de viragem
- se roda no sentido dos ponteiros do relógio ou não
- se a mudança de comprimento é crescente ou decrescente.

Vejamos o código.


import cTurtle

def espiral(comp_min, comp_max, passo, angulo):
"""
Desenho de espirais por justaposição de segmentos de recta que
vão rodando de um certo ângulo. Assumo sentido crescente e rotação
idêntica à dos ponteiros do rrelógio.
"""
cTurtle.down()
for segmento in range(comp_min, comp_max, passo):
cTurtle.forward(segmento)
cTurtle.right(angulo)
cTurtle.up()
cTurtle.hideturtle()


Com a chamada espiral(10,150,5,90) obtemos a figura:





Mas se usarmos outros valores, como espiral(5,50,2,33), o desenho será outro:



.

Divirta-se!