Arquivo

Arquivo do Autor

Space Oddity com o Comandante Chris Hadfield

terça-feira, 14 maio 2013; \20\UTC\UTC\k 20 Deixe um comentário

Apenas tentem assistir a esse vídeo sem se emocionar.

Categorias:Ars Physica

Extendendo Python com C/C++ via PyBindGen e CTypes

sábado, 5 nov 2011; \44\UTC\UTC\k 44 6 comentários

Depois de um tempo sem postar no Ars Physica vim postar sobre algo totalmente diferente do que eu costumo escrever por aqui: programação. Como grande parte dos físicos hoje em dia, meu dia-a-dia consiste em grande parte em escrever programas de computador para resolver problemas e fazer cálculos. Todo começo de projeto de programação impõe um dilema para quem vai dedicar as próximas semanas (ou meses, anos…) escrevendo uma nova ferramenta: que linguagem de programação usar? Eu escolhi a combinação de C/C++ e Python.

As razões para essa escolha são muitas: Python é uma linguagem bastante simples, que permite prototipagem rápida e desenvolvimento de soluções com pouca dor de cabeça, e com uma ampla gama de módulos e bibliotecas prontas para os mais diversos fins (numpy, scipy, matplotlib, entre centenas de outras…). Entretanto código escrito puramente em Python é extremamente lento, por diversas razões. Isso faz com que não seja possível escrever uma simulação em python puro se pretende-se ter resultado em um tempo razoável. O ideal portanto é usar como cavalo de carga uma outra linguagem, que seja capaz de produzir binários eficientes, que rodem rápido no seu computador. Essa linguagem deve ser usada nas partes onde eficiência e tempo de execução são críticos, enquanto o Python pode ser usado para lidar com partes que geralmente são chatas de se fazer nessas linguagens de mais baixo nível: lidar com strings, arquivos, operações de sistema, geração de código, parsing,…

Como exemplo, no meu atual projeto no doutorado eu uso C/C++ para fazer uma simulação de Monte Carlo, e o Python para organizar as simulações, rodar a simulação para diversos valores de parâmetros diferentes, salvar os resultados em arquivos organizadinhos, enviar os processos para rodar nos diversos nós do cluster do departamento, etc.

Existem dezenas de formas de integrar Python com outras linguagens, de C/C++ e Fortran até Haskell e Emacs Lisp. Entretanto até hoje eu usava a mais boba: compilava um programa em C ou C++ que aceitava parâmetros de linha de comando, e de dentro do código do python abria um pipe para chamar o executável C com os parâmetros adequados com uma chamada de sistema. É uma gambiarra que funciona, mas não deixa de ser uma gambiarra. O ideal é compilar o seu código como uma biblioteca compartilhada que exporta objetos que o interpretador do Python consegue ler. A forma padrão de fazer isso é importar o cabeçalho ‘Python.h’ e usar o API contido lá para criar esses objetos. Isso não é exatamente difícil de fazer, mas é um trabalho sacal e bem repetitivo. É bom ter formas de automatizar esse trabalho e apenas se preocupar em escrever bem seu código em C, sem se preocupar se ele vai ser ou não carregado no python depois.

CTypes

Se o seu código é em C (e não C++) a maneira mais fácil de fazer isso é usando o CTypes – um módulo presente na biblioteca padrão do Python capaz de carregar bibliotecas compartilhadas feitas em C. Por exemplo, suponha que você deseja criar uma função que some dois inteiros e retorne o resultado. O código fonte está nos arquivos teste.h e teste.c:

//arquivo: teste.h
int add(int x, int y);

//arquivo: teste.c
#include "teste.h"
int add(int x, int y){
  return (x + y);
}

Note que esse é um código em C “vanilla”, sem nenhuma referência ao fato de que ele será depois usado no Python. Tudo o que é preciso para disponibilizar a função ‘add’ no python é compilar esse código como uma biblioteca compartilhada:

gcc -fPIC -o libteste.o -c teste.c
gcc -shared -o libteste.so libteste.o

Isso deve gerar um arquivo ‘libteste.so’, que é um binário que possui as instruções da função ‘int add(int, int)’ de forma que pode ser acessado por outros binários em C. Para chamar esse binário dentro do Python com o CTypes é muito fácil:

from ctypes import cdll

libteste = cdll.LoadLibrary("./libteste.so")
# eh necessario passar o caminho completo para o binario pois ele nao esta no PYTHONPATH
x = libteste.add(5, 2)
print x

Esse script deve retornar o valor ‘7’, conforme esperado. Difícil, né?

Quando sua função retorna um tipo que não seja ‘int’, é necessário ainda informar ao Python qual é o tipo adequado para converter os objetos do python antes de passá-los para a função em C. O CTypes oferece uma gama de tipos correspondentes a todos os tipos que podem ser criados em C padrão:

Tipo no CType Tipo no C Tipo no Python
c_bool _Bool bool (1)
c_char char 1-character string
c_uint unsigned int int/long
c_long long int/long
c_float float float
c_double double float
c_char_p char * (NUL terminated) string or None

Por exemplo, considere a seguinte função:

//arquivo: teste.h
double c_raizq(double x);

//arquivo: teste.c
#include <math.h>
#include "teste.h"

double c_raizq(double x){
  return sqrt(x);
}

Nesse caso, ao abrir a biblioteca (compilada exatamente como antes) será necessário dar mais informação a respeito dos tipos dessa função:

from ctypes import cdll
from ctypes import *

libtest = cdll.LoadLibrary("./libtest.so")
raiz = libtest.c_raizq
raiz.restype  = c_double
raiz.argtypes = [c_double]

x = raiz(2)

print x

Toda função importada do C tem as duas propriedades ‘restype’ – que é o tipo que a função deve retornar – e ‘argtypes’ – que é uma lista dos tipos que essa função recebe como parâmetros, na ordem em que eles aparecem no código em C.

Quando for necessário usar ponteiros, arrays, structs ou enums, a coisa pode ficar um pouquinho mais complicada, mas nada que faça o código crescer muito mais do que isso. Por exemplo, suponha que queremos exportar o seguinte código para o Python:

//arquivo: teste.h

struct cvec{
  double x;
  double y;
};

typedef struct cvec vector;
double norm(vector * point);  

//arquivo: teste.c

#include "teste.h"
#include <math.h>

double norm(vector * point){
  return sqrt(point->x * point->x + point->y * point->y);
}

Precisamos de uma estrutura similar ao struct ‘vector’ e de portar a função ‘norm’. Note que o argumento dessa função é um ponteiro para a struct vector. O código Python para fazer isso segue abaixo:

from ctypes import cdll
from ctypes import *

#imitando a struct vector 
class vector(Structure):
    _fields_ = [("x", c_double) ,
                ("y", c_double)]

libtest = cdll.LoadLibrary("./libtest.so")
norm = libtest.norm
norm.restype  = c_double
norm.argtypes = [POINTER(vector)]

vecc = vector(5,2)
print norm(pointer(vecc))

A classe vector imita a estrutura do struct vector, e as funções POINTER e pointer são usadas respectivamente para informar que o tipo do argumento é um ponteiro e obter um ponteiro para o objeto ‘vecc’. Structs e unions deve ser replicadas no Python por classes que herdam das superclasses Structure e Union, respectivamente.

Enfim, o CTypes fornece um API completo para usar qualquer código C padrão dentro do Python com um mínimo de boilerplate e nenhuma interferência no código original. Não é preciso reescrever suas funções nem entender a estrutura do API do Python. Apenas compilar seu código como uma biblioteca compartilhada.

PyBindGen

Infelizmente o CTypes não é capaz de ler binários de C++. A razão é simples: não existe um padrão para os binários de C++ e cada compilador implementa interfaces diferentes para seus binários. A esperança é que com o estabelecimento do padrão C++11 isso possa ser resolvido, mas isso é uma questão para o futuro. No entanto existe uma biblioteca feita em Python capaz de gerar bindings de códigos em C++ sem interferir no código e com o mínimo de esforço. Por exemplo, suponha que temos uma classe feita em C++ que representa pontos em 2 dimensões, com alguns métodos úteis:

//arquivo Vector.hpp
#include <cmath>
class Vector {
private:
  double x;
  double y;
public:
  Vector(double _x, double _y) : x(_x), y(_y) {}; //construtor

  double norm();               // retorna tamanho do vector
  void reflectO();           // reflete o vetor através da origem
  void rotate(double theta); // roda o vetor em torno da origem por um angulo theta
};

//arquivo Vector.cpp
#include "Vector.hpp"

double Vector::norm() {
  return x*x + y*y;
}

void Vector::reflectO(){
  x = -x;
  y = -y;x
}

void Vector::rotate(double theta){
  double xx = cos(theta) * x - sin(theta) * y;
  double yy = sin(theta) * x + cos(theta) * y;
  x = xx;
  y = yy;
}

Essa classe cria um vetor com duas componentes, com métodos que calculam a norma, refletem o vetor através da origem e rodam por um certo angulo. Para tornar essa classe disponível para o Python é preciso criar um script que gera automaticamente os bindings que devem ser então compilados em um módulo. A estrutura do script é bem simples – primeiro você deve criar um módulo e adicionar ao módulo a classe que deseja exportar, e em seguida adicionar os métodos à classe:

#arquivo: setupBinding.py
#! /usr/bin/env python

import sys
import pybindgen
from pybindgen import param, retval

#Modulo Vector
mod = pybindgen.Module("Vector")

#o modulo inclui o header Vector.hpp
mod.add_include('"Vector.hpp"')

#Adicionando a classe:
klass = mod.add_class('Vector')

#Adicionando o construtor:
klass.add_constructor([param('double', '_x'), param('double', '_y')])

#Adicionando os metodos:
klass.add_method('norm', retval('double'), [])
klass.add_method('reflectO', None, [])
klass.add_method('rotate'  , None, [param('double', 'theta')])

#imprime o binding na tela
mod.generate(sys.stdout)

Note a sintaxe dos comandos:

  • add_constructor([param(‘tipo’, ‘nome’),…]) – essa função recebe uma lista com os parametros que o construtor recebe. Se houver mais de um construtor, eles devem ser todos adicionados em sequencia.
  • add_method(‘nome’, retval(‘tipo de retorno’), [param(‘tipo_do_parametro1’, ‘nome1’), …]) – essa função recebe o nome do método, o tipo do valor que o método retorna e uma lista com os tipos dos parametros de entrada.

Ao rodar esse script com ‘python setupBinding.py’, ele imprime na tela um código em C que é um binding para o código contido em ‘Vector.cpp’ e ‘Vector.hpp’. Ao compilar esses bindings, teremos um módulo Vector que pode ser importado dentro do python como qualquer outro módulo:

import Vector

foo = Vector.Vector(1,2)
print foo.norm()
foo.rotate(0.2)

Compilar esse módulo é só um pouquinho mais complicado do que no caso do CTypes. Em primeiro lugar é preciso compilar uma biblioteca compartilhada como anteriormente:

g++ -fPIC -c -o libvector.o  Vector.cpp
g++ -shared  -o libvector.so libvector.o

sh Isso cria os arquivos ‘libvector.o’ e ‘libvector.so’. E então devemos gerar os bindings:

python setupBinding.py > bindVector.c

sh E compilar uma biblioteca compartilhada com os bindings:

g++ -fPIC -I/usr/include/python2.7 -c -o bindVector.o bindVector.c
g++ -shared -o Vector.so -L. -lvector bindVector.o

Note que é preciso passar para o compilador o caminho para os headers do python no seu sistema – no meu caso a versão 2.7 do python no linux está em ‘usr/include/python2.7‘. Também é preciso passar para o linker o caminho atual, onde está os arquivos ‘libvector.so’ e ‘libvector.o’ – que é a pasta atual onde a compilação está sendo feita. Isso é feito com as flag “-L. -lvector”. Isso cria o arquivo Vector.so, que contém o módulo Python que pode ser carregado através do comando “import”. Note que o nome do arquivo deve ser o mesmo nome do módulo conforme adicionado no script que gerou os bindings.

Antes de tentar importar o arquivo no python, é preciso adicionar o caminho onde o arquivo ‘Vector.so’ se encontra nas variáveis de ambiente PYTHONPATH e LD_LIBRARY_PATH:

export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:.
export PYTHONPATH=$PYTHONPATH:.

Agora o módulo Vector pode ser usado normalmente:

import Vector

foo = Vector.Vector(1,2)
print foo.norm()
foo.rotate(0.2)

Enfim. Espero que isso ajude quem, como eu, vem quebrando a cabeça com isso a muito tempo e já testou diversas ferramentas (SWIG, SIP, Cython/Pyrex, Boost::Python, etc, etc, etc… ). As documentações oficiais das ferramentas usadas nesse post podem ser encontradas aqui:

Org2Blog – integrando o org-mode do emacs ao seu blog do wordpress.

quinta-feira, 21 abr 2011; \16\UTC\UTC\k 16 13 comentários

Este é um teste do sistema de postagem org2blog, que transforma textos do org-mode do emacs para posts de blog do wordpress. Esse é o melhor sistema de postagem para wordpress que eu encontrei até agora. O org-mode é um modo de edição de arquivos de texto estruturados no editor de texto emacs. Uma das grandes vantagens do org-mode é a possibilidade de exportar seus textos para diversos formatos – como um documento em latex ou html, uma apresentação do beamer, um livro em docbook,… e agora, com o add-in org2blog, posts de blogs para o wordpress.

As vantagens são inúmeras:

  • EDITAR NO EMACS!!!
  • o org-mode tem uma sintaxe muito simples para estruturar textos com seções, subseções, incluir links, listas, tabelas e etc.
  • editar no emacs te permite usar macros e scripts para fazer geração dinâmica de textos,
  • o org-mode permite adicionar equações em latex, como se fosse em um documento latex normal, e traduz isso para a sintaxe do wordpress – \int e^{ikx} dk = 2\pi\delta(x).
  • o org-mode-babel permite adicionar código em diversas linguagens de programação e editá-las usando seu modo natural no emacs. O código é automaticamente colorido com syntax-highlighting (para a linguagem correta!) e postado usando as tags adequadas no wordpress. Veja por exemplo esse código em Haskell:
    sort :: (Ord a) => [a] -> [a]
    sort (x:xs) = (filter (<x) foo) ++ [x] ++ (filter (>=x) foo)
      where foo = quicksort xs

    O org-mode também pode executar o código, compilar e testar.

  • o org-mode possui dezenas e dezenas de ferramentas para lidar com texto,
  • exportar não apenas para wordpress mas para dezenas de outros formatos.

Enfim, essas são apenas algumas das vantagens. Eu comecei a usar o org-mode para editar apresentações de slides em beamer. Por muito tempo eu reclamei que não existia uma forma fácil de se fazer isso, e o org-mode foi a saída perfeita para mim. Agora o org2blog vem sanar uma outra séria deficiência de ferramentas na minha opinião: como editar de forma fácil posts de blog com código-fonte e latex simultaneamente.

Instalação do org-mode

Instalar o org-mode é muito fácil. Primeiro de tudo você precisa do emacs, claro. Vou assumir que você está no linux (sinceramente, se você está no windows eu recomendaria que instalasse o linux primeiro, porque eu nem sei fuçar no win-emacs 😛 ). Você deve baixar e descompactar o org-mode no site e colocá-lo na sua pasta de add-ons do emacs (tipicamente na pasta ‘~/.emacs.d/’). Abra então o terminal na pasta e dar os comandos típicos:

make
make doc
sudo make install

Depois adicione no seu arquivo de configuração do emacs (tipicamente ‘~/.emacs’ ou ‘~/.emacs.d/init.el’, o que você preferir) as seguintes linhas (ajustando para os diretórios adequados):

(setq load-path (cons "~/.emacs.d/org-mode/lisp" load-path))
(setq load-path (cons "~/.emacs.d/org-mode/contrib/lisp" load-path))
(require 'org-install)
(org-babel-do-load-languages
 'org-babel-load-languages
 '((R . t)
   (emacs-lisp . t)
   (haskell . t)
   (gnuplot . t)
   (latex   . t)
   )) ;; adicione aqui as linguagens que quiser que o org-mode reconheça. 

Para manter atualizado você pode baixar os arquivos do repositório git do org-mode, conforme as instruções no site. Veja o manual do org-mode para todas as instruções de como usá-lo. Para configurar o org-babel, a parte do org-mode que lida com códigos, veja essa página e essa pagina.

Instalação do org2blog

O org2blog, com instruções de instalação, pode ser encontrado no github do punchagan. Baixe os arquivos usando o git, conforme indicado no README, no seu diretório ‘~/.emacs.d’ do emacs. Siga o README para saber como configurar o seu emacs para logar automaticamente no seu blog e colocar o seu post.

Enfim. Não tem mais muito o que dizer. Eu fiquei muito empolgado com a possibilidade de editar meus posts no emacs com calma e só postar depois de pronto. O org-mode tem diversas ferramentas para lidar com texto que o tornam de longe a melhor ferramenta de editoração eletrônica para emacs – para textos em latex e apresentações particularmente. Além disso ele tem coisas como o record-mode e outras ferramentas para lidar com todo-lists e agendas. Vale a pena dar uma olhada.

Boa sorte.

Categorias:org2blog Tags:, , ,

The Joy of Haskell, parte 1 – Introdução

segunda-feira, 18 abr 2011; \16\UTC\UTC\k 16 1 comentário

Como alguns devem ter percebido, eu me tornei recentemente um entusiasta da linguagem de programação chamada Haskell. Eu até criei um blog para postar sobre isso, e coloquei propaganda dele aqui. O Rafael Lopes de Sá me convenceu de que não era necessário fazer isso e que eu poderia mesmo postar aqui sobre isso, então resolvi fazer um post introdutório sobre Haskell, para que os meus posts seguintes façam mais sentido.

Porque Haskell?

O que é tão atraente nessa linguagem para mim? É uma linguagem um pouco estranha, com uma curva de aprendizado um pouco complicada e as vezes parece necessário um esforço bem maior para fazer coisas que são simples em outras linguagens. Porque não C? O que Haskell faz que C não faz? Ora, nada. C e Haskell são duas formas diferentes de escrever essencialmente os mesmos comandos fundamentais. Mas há razões para eu preferir Haskell.

O primeiro é que Haskell é uma linguagem de altíssimo nível. Calma, isso não é um juízo de valor. Uma linguagem de baixo nível é uma linguagem que opera com poucas camadas de abstração entre o código e o que será de fato executado na máquina. C permite fazer operações de baixo nível: manipular memória, executar instruções asm, etc… Linguagens de alto nível escondem esses detalhes em abstrações lógicas, de modo você que nunca vai precisar se preocupar com detalhes de hardware. Haskell é uma linguagem que opera em níveis de abstrações muito mais altos que o normal. Haskell existe em um universo bastante independente do fato de que aquilo será compilado e executado em um computador físico. É uma linguagem bastante matemática e abstrata. E mesmo assim é eficiente. Há outras linguagens abstratas de alto nível – como Perl, Lisp, ML,… Mas os compiladores de Haskell são particularmente eficientes, e capazes de produzir códigos que rodam com pouca perda de desempenho se comparados a C.

O segundo é que Haskell agrega certas características que a tornam muito próximas de um sistema lógico-matemático. Muito de Haskell é baseado em uma formulação da matemática chamada Cálculo Lambda. O cálculo lambda é uma sistema formal alternativo ao sistema baseado em teoria de conjuntos. Ele pode ser usado para re-escrever a matemática que conhecemos em outras bases. Haskell é muito próximo de algo chamado cálculo lambda tipado. Isso por si é bem atraente, e há matemáticos que usam Haskell para criar sistemas formais para provar teoremas, etc. Mas para mim o melhor disso é que criar mesmo estruturas matemáticas úteis (espaços vetorias, grupos, espaços de probabilidade,etc…) em Haskell é bem natural.

Haskell é expressivo. Isso é um valor muito subjetivo, mas eu acho que o sistema de tipos de Haskell permite expressar conceitos de forma muito legível. O tipo de um objeto em Haskell traz muita informação sobre o que aquele objeto faz. Muitas vezes basta saber o tipo para saber exatamente como aquilo deve ser implementado.

Finalmente, Haskell é um exercício intelectual interessante. Eu acho estimulante programar em Haskell e acho que me fez um programador melhor mesmo quando estou usando outras linguagens.
Há outras vantagens no Haskell – como o fato de que a trasparência referencial e a avaliação não-estrita tornarem a paralelização de programas algo bem simples. Alguns dizem que linguagens influenciadas por Haskell (como as últimas versões de C#, Scala, OCaML, …) são linguagens do futuro, pois permitem fazer computação concorrente e paralela de forma trivial. Eu acho isso um overstatement, mas certamente elas vão ficar importantes.

Mas eu realmente não ligo muito pra isso. Eu gosto de Haskell como um fim em si. É quase como se fosse o meu Sudoku ou o meu Cubo de Rubik – um passatempo intelectual interessante. Isso tudo não faz de Haskell uma linguagem melhor por si só, mas quando combinado com um certo tipo de personalidade de programador, a combinação fica bem eficiente.

O que é Haskell?

Haskell é uma linguagem de programação com algumas características:

  • é funcional,
  • pura (com transparência referencial),
  • não-estrita,
  • com tipos estáticos,
  • polimorfica (com variáveis de tipo e typeclasses)

todas essas coisas serão entendidas ao longo de vários posts. São conceitos abstratos de computação que são mais fáceis de entender quando vemos um código.

Em primeiro lugar, antes de falar sobre isso, vamos ver como usar o Haskell. Você pode facilmente preparar seu computador para programar em Haskell instalando algo chamado Haskell Platform – no Ubuntu pode ser instalado via apt-get ou synaptic, no windows e em outros sabores de linux é só baixar do site o binário (http://hackage.haskell.org/platform/). O haskell platform vem com várias ferramentas, entre elas o compilador Glasgow Haskell Compiler (GHC), que contém também um modo interativo chamado GHCi, e o gerenciador de pacotes Cabal, que é usado para instalar bibliotecas de maneira bem simples.

O GHCi é um modo interativo, bem parecido com o que se encontra em outras linguagens como Python. É um loop com um cursor que recebe comandos. Você pode colar um pedaço de código lá e ele será executado. É a melhor forma de começar a aprender. Você pode começar digitando uma expressão matemática qualquer e receber a resposta assim que pressionar `Enter`:

/> 2 + 2
 4
/> 4 * 5 + 2
 22

Um programa em Haskell é essencialmente isso: uma expressão cujo valor deve ser encontrado através de um processo de “avaliação” (evaluation – não sei se essa é a melhor tradução). Essa é a essência de uma linguagem funcional – o fato de que o código é escrito como uma expressão, resultado da aplicação de funções sobre outras expressões, e o objetivo final do código é encontrar o valor daquela expressão. Algo como aqueles exercícios que você fazia na 6ª série: “Efetue: …” e uma expressão complicada com números e operadores era dada, para que você encontrasse o valor daquela expressão.

Todo objeto em Haskell é uma expressão, com um valor bem definido. E todo valor tem um tipo bem definido. Há tipos básicos, Int (inteiros), Char (caracteres), Double (ponto flutuante de dupla precisão), Bool (booleanos), etc… e tipos mais abstratos, sobre os quais vou falar mais tarde – os tipos algébricos, que são o “bread and butter” do Haskell. Você pode dar um nome para uma expressão, para resumir a construção de outras expressões. Se você editar um arquivo chamado “teste.hs” com o seguinte conteúdo:

> -- arquivo teste.hs
> x :: Int
> x = 20
> y :: Int
> y = 5

Você pode carregá-lo no GHCi da seguinte forma:

/> :l teste.hs
[1 of 1] Compiling Main ( foo.hs, interpreted )
Ok, modules loaded: Main.
/> x
20
/> x + y
25
/> let z = x + y
/> z
2

Para criar nomes dentro do GHCi é preciso usar a cláusula “let”. Em um arquivo separado não é preciso.

Note a sintaxe: x::Int. Isso significa “vou dar o nome x a uma expressão que tem tipo Int”. Isso não é uma declaração de variáveis como é comum em linguagens imperativas. Isso é só a definição de um nome. Não existem “variáveis” em Haskell como existe em C, um espaço reservado de memória cujo conteúdo pode ser manipulado. Um nome é um nome definitivo – aquele nome é um mero sinônimo para a expressão que ele representa. Um nome não pode mudar de valor. Se você tentar colocar:

> x :: Int 
> x = 10
> x = 20

em um arquivo, quando tentar carregá-lo obterá um erro:

Multiple declarations of `Main.x'
 Declared at: dah.hs:1:0
 dah.hs:3:0

Alguns tipos algébricos importantes são fornecidos na biblioteca padrão, chamada Prelude. Por exemplo, as listas:

> xs :: [Int]
> xs = [3,4,32]

Uma lista é uma sequencia ordenada de valores do mesmo tipo. Uma lista de objetos de tipo a tem tipo [a]. String é um sinônimo para [Char]:

/> :t "rafael"
"rafael" :: [Char]
/> :t ("rafael" :: String)
 ("rafael" :: String) :: String

Outro tipo composto comum é na verdade uma família de tipos chamados “tuplas”. São sequencias ordenadas de objetos de tipos que podem ser iguais ou não:

> tupla :: (Int, Double)
> tupla = (5, 3.14)

A principal diferença entre tuplas e listas é que listas de tamanhos diferentes tem o mesmo tipo, desde que os objetos internos seja do mesmo tipo:

> ys :: [Int]
> ys = [2,3,2,3,4,22,3,2,4,2,4]

Já tuplas de tamanhos diferentes têm tipos diferentes:

> tupla' :: (Int, Int, Double)
> tupla' = (5, 3, pi)

Tuplas e listas podem ser combinadas para fazer tipos bem complicados:

> foo :: [(Int, Double)]
> foo = [(1, 1.2), (3, 2.3)]
> bar :: (Int, (Int, Char), [String])
> bar = (1920, (0, 'a'), ["Haskell", "É", "Legal"])

Se eu não posso alterar que expressão um nome armazena, como faço computação em Haskell? Eu crio funções. Funções são objetos que recebem uma entrada e retorna uma saida. Por isso elas têm tipo (a -> b) onde a é o tipo do valor de entrada e b o tipo do valor de saída:

> succ, pred :: Int -> Int
> succ x = x + 1
> pred x = x - 1

Uma computação em Haskell é feita através da aplicação de funções sobre expressões – múltiplas funções são combinadas para que, quando aplicadas a uma expressão de entrada, produzirem o resultado desejado. Em Haskell funções são expressões como outras quaisquer. Elas podem ser entradas e saídas de outras funções. Eu posso ter uma função que recebe outra função como parâmetro ou retorna outra função como resultado. Por exemplo, eu posso ter uma função:

> foo' :: (Int -> Int) -> Int
> foo' f = (f 0)

Para qualquer função f::(Int -> Int), essa função retorna o valor de f calculado em 0. No futuro veremos casos mais úteis disso. Eu disse que funções são expressões como outras quaisquer. Se eu posso escrever expressões sem ter que dar um nome para elas, tem que haver um jeito de fazer isso com funções também, né? São as chamadas expressões lambda (também conhecidas como “closures” em outras linguagens). Eu posso aplicar a função foo’ em uma função anonima assim:

/> foo' (\ x -> x + 1)
1

A expressão (\ x -> expr ) deve ser interpretada assim: uma função que, quando recebe um número x, retorna expr. Portanto (\ x -> x + 1) é a função que quando aplicada em x, retorna x+1. Se eu avaliar a expressão foo’ (\ x -> x + 1) terei:

foo' (\ x -> x + 1)
(\x -> x + 1) 0
0 + 1
1

As vezes funções que recebem ou retornam funções são chamadas de funções de segunda ordem.

Eu disse que funções tem apenas uma entrada e uma saída. Mas e quando eu preciso de mais de um dado de entrada para produzir um resultado? Eu posso usar tuplas:

> soma :: (Int, Int) -> Int
> soma (x,y) = x + y

Não parece muito prático. Mas existe um teorema em cálculo Lambda que diz o seguinte: uma função de duas entradas é isomórfica a uma função que recebe apenas uma entrada e retorna uma função. Como assim? . Imagine que eu reescrevesse a função soma assim:

> soma :: Int -> (Int -> Int)
> soma x = (\y -> x + y)

O que acontece quando eu aplico essa função em um número? O resultado de (soma 1) é (\y -> 1 + y). Ou seja, (soma 1) é uma função que quando aplicada em y, me retorna 1 + y. Então ((soma 1) 2) = 3. Para facilitar a vida do programador, o compilador de haskell entende que (soma 1 2) significa: aplique soma ao número 1 e depois aplique a função resultante ao número 2. O compilador também permite escrever:

> soma :: Int -> Int -> Int
> soma x y = x + y

O compilador também entende a sintaxe (\ x y -> expr…). Isso é traduzido automaticamente para (\ x -> (\ y -> expr…)). A aplicação da função sobre um valor retornando uma função que aguarda outro valor é por vezes denominada aplicação parcial.

Note que o tipo a -> b -> c deve ser sempre interpretado como a -> (b -> c), nunca como (a -> b) -> c. Note a diferença: o primeiro recebe um valor e retorna uma função, o segundo recebe uma função e retorna um valor.

Você já percebeu nesse momento uma coisa: todos os nomes de expressões são em minúsculas e os nomes de tipos em maiúsculas. E também já percebeu que de vez em quando eu uso a, b, c para denotar um tipo qualquer. O compilador de Haskell entende isso. Isso é chamado polimorfismo paramétrico. Para entender vamos dar uma olhada na função de segunda ordem que implementa o padrão mais tipico do Haskell: a composição de funções. Suponha que eu queira aplicar as funções succ e pred em sequencia sobre um número. Eu posso fazer:

/> pred (succ 0 )
 0

Note que eu posso aplicar a combinação (pred (succ x)) em qualquer x. Eu posso ter a função

> bar' = (\ x -> pred (succ x))

Esse é um padrão independente do que fazem as funções pred e succ. Aliás, é independente do fato de que eu estou falando de números inteiros. Apenas depende de um fato: eu tenho duas funções cujos tipos são compatíveis: o tipo que succ retorna é compatível com o tipo de entrada de pred. Considere a seguinte função de segunda ordem:

> composicao f g x = f (g x)

Ela recebe duas funções (f e g) e um valor (x) e retorna a aplicação sucessiva dessas funções ao valor dado. Qual é o tipo dessa função? Vamos deixar o compilador inferir para nós:

/> :t composicao
composicao :: (t1 -> t2) -> (t -> t1) -> t -> t2

Ou seja: quaisquer que sejam as funções f e g, essa função faz sentido, desde que o tipo de saida de g seja o tipo de entrada de f. Essa função já existe na biblioteca padrão, e é chamada (.). Sua definição é:

> (.) :: (b -> c) -> (a -> b) -> a -> c
> (f . g) x = f (g x)

A aplicaçao parcial de (.) sobre duas funções retorna a função composta (no sentido matemático mesmo). Ou seja: (f.g) = (\ x -> f (g x)). Isso funciona para quaisquer tipos a,b e c e quaisquer funções que satisfaçam os tipos da declaração de (.). Isso quer dizer que (.) é uma função polimórfica – ou seja, uma família de funções que pode ser especializada para vários tipos diferentes. Exemplos:

> foo = sin . cos
> bar = succ . length

A função foo é a composição das funcções sin :: Double -> Double e cos :: Double -> Double. O resultado de (foo x) é sin(cos x). A função bar é a composição de succ, que calcula o sucessor de um número inteiro, com a função length, que calcula o tamanho de uma lista de um tipo qualquer:

> length :: [a] -> Int
> succ :: Int -> Int
> (succ . length) :: [a] -> Int

Funções desse tipo – que compõe operações simples para realizar operações complexas, são o arroz com feijão da programação funcional. Quase todas as funções importantes da biblioteca básica são funções polimórficas de segunda ordem. Veremos várias em breve – map, ($), (>>=), replicate, concat, concatMap, zip, …

Enfim. Acho que é o suficiente por hoje. Na próxima vou falar das coisas mais legais do Haskell que são os tipos algébricos e as classes. Depois vou discutir um pouco sobre as características da linguagem – o fato de ser fortemente tipada, de ter transparência referencial e avaliação não-estrita.

Categorias:Ars Physica

Verdades, mentiras e estatisticas na campanha eleitoral

quarta-feira, 13 out 2010; \41\UTC\UTC\k 41 3 comentários

Peço licença aos meus co-blogueiros para falar sobre as eleições presidenciais. Uma vez que eu não vou emitir nenhum juízo sobre nenhum dos candidatos, nem explicitar preferência alguma, creio que não há problema. Na verdade o tema eleitoral é só uma desculpa para falar sobre estatística :P. Caso haja problema, por favor me avisem.

Nessa campanha presidencial – como, aliás, deve ser em qualquer campanha eleitoral – tem acontecido uma fenômeno interessante nas propagandas e discursos de aliados de cada um dos candidatos do segundo turno. Ambas as campanhas tentam comparar os governos de Lula e FHC apresentando todo tipo de números e estatísticas. O interessante é que o cenário parece estranhamente ambíguo: para cada estatística que mostra Lula melhor que FHC existe outra que mostra o exato contrário. Para dois exemplos interessantes desse tipo de campanha, veja esses dois links:

Esse fenômeno pode parecer estranho para os espectadores da campanha menos acostumados aos números. Afinal, quem foi melhor para o ensino superior, FHC que aumentou o número de matrículas ou Lula que criou mais universidades? Quem diminuiu mais a pobreza, FHC que aumentou 4 vezes mais o IDH ou Lula que criou 3 vezes mais empregos?

Não há nada de estranho aí. O que está por trás dessa estranheza é uma falácia estatística que pode ser chamada “falácia do atirador”. Imagine um homem que quer demonstrar que é um excelente atirador e te mostra um alvo pintado em um campo de tiro, com 10 tiros certeiros na mosca. Você pode achar que ele é um grande atirador mesmo, mas sabe como ele produziu esse resultado?

O atirador ergueu uma enorme parede de madeira, de 10 metros de largura e 5 de altura, colocou-se na posição de tiro e descarregou 500 tiros contra a parede, sem tentar mirar particularmente em nenhuma posição. Claro que depois disso a parede estará cravejada de buracos e em alguns lugares haverá buracos de tiro mais próximos um dos outros. O atirador escolhe convenientemente 10 buracos que, ao acaso, ficaram bastante próximos entre si e desenha e pinta o alvo em torno deles. Então ele corta o resto da madeira e recoloca o alvo em sua posição original, com 10 tiros “certeiros” na mosca.

O homem não é um excelente atirador. Ele apenas escolheu o alvo depois de ter os resultados. Ele selecionou os “bons” resultados e descartou os ruins. Ele transformou uma distribuição bastante larga em uma distribuição mais estreita apenas descartando certos resultados e mostrando outros.

Como isso se aplica à campanha eleitoral?

Para cada aspecto de um governo que você queira avaliar, existe um sem número de estatísticas que podem ser usadas. Se, por exemplo, eu quero avaliar a evolução da renda, posso mostrar o crescimento do PIB per capita, ou de algum índice de salários, ou da fração do PIB correspondente aos salários, ou quanto subiram os salários em comparação com a taxa básica de juros, ou comparar com taxas “reais” praticadas no mercado. Posso comparar esses números em dólares ou reais, posso comparar o poder aquisitivo real, ou quanto essa renda compra de uma certa cesta de produtos essenciais. Posso focar apenas no crescimento da renda da classe C, ou em quanto cresceu (ou caiu) a razão da renda da classe C pela renda da classe A. Posso comparar quantos bens de consumo essenciais as pessoas conseguem comprar, ou posso comparar quanto o crescimento de suas rendas se compara com o rendimento de um certo investimento padronizado. Todas essas são formas de comparar quanto a renda cresceu.

Deu para perceber que existe um grande número de estatísticas para comparar dois governos, mesmo que fiquemos apenas no restrito conjunto de estatísticas referentes ao aumento da renda. Se eu comparar todos esses números entre o governo A e o governo B, alguns resultados serão pró-A e outros serão pró-B. É natural que seja assim por uma razão simples: há uma flutuação incrível nesses números. Flutuações temporais, flutuações causadas por diferentes metodologias ou mesmo flutuação que resulta do processo de amostragem. A incerteza nesses números as vezes é muito grande, e medidas em semanas diferentes podem causar flutuações de vários pontos percentuais. Não temos um valor determinado para esses números, temos uma distribuição de probabilidades que representa o quanto sabemos sobre eles. E essa distribuição é relativamente larga.

Então existe uma probabilidade de que cada estatística seja pró-A ou pró-B, ainda que os governos A e B tenham sido mais ou menos parecidos. E mesmo que o governo A tenha sido muito melhor que o governo B em certo sentido, ainda assim teremos uma certa probabilidade de ter um certo número de estatísticas pró-B. Mas eu sempre posso escolher que fração das estatísticas que eu pretendo mostrar será pró-A ou pró-B. Eu posso apenas mostrar 100% de estatísticas pró-A e argumentar assim que o governo A foi incrível. Isso é bem ilustrado pela famosa propaganda da Folha de São Paulo de alguns anos atrás, em que se apresenta diversas estatísticas positivas do governo de Adolf Hitler na Alemanha, que certamente foi um governo desastroso!!!

Então é impossível comparar dois governos com estatísticas? Claro que não. É perfeitamente possível. Apenas é necessário fazê-lo de forma sistemática, com métodos claros, com padrões e referências bem definidos. Existem procedimentos para se evitar a falácia do atirador em estudos estatísticos. Por exemplo, pode-se escolher que estatísticas serão calculadas de antemão, antes da colheita de dados, de acordo com um método bem definido. Isso evita que se “desenhe o alvo” em torno do resultado desejado. Pode-se fazer uma análise de sensitividade, mostrando que ainda que a metodologia fosse diferente, o resultado não seria tão diferente assim. Enfim, existem técnicas para isso.

Mas isso é algo que campanhas eleitorais nunca serão capazes de fazer. Elas são enviesadas por princípio, a cesta de índices que escolhem para mostrar é viciada e sua interpretação errônea e vazia. E isso vale para qualquer campanha, independente da orientação ideológica do candidato. É inevitável. Não chega nem a ser desonestidade, é da natureza da propaganda. O ideal seria que, ao invés de usar os números de forma leviana, fossem contratados estatísticos profissionais e neutros para criar essas análises. Mas isso nunca vai acontecer. 😉

O melhor é que o eleitor esteja atento às formas com que os números podem ser usados contra ele. Números adequadamente escolhidos podem defender qualquer estória que se deseje contar. Mas não fique achando que toda estatística é resultado de manipulação. Há métodos adequados para se evitar a manipulação, mesmo a manipulação involuntária.

Há uma citação de natureza ética difundida entre os estatísticos adequada para fechar essa discussão. Infelizmente não me lembro o autor ou a exata fraseologia, mas a essência é: é sempre possível mentir usando a estatística, mas é impossível dizer a verdade sem ela.

A física da pesquisa e a física da sala de aula

quarta-feira, 29 set 2010; \39\UTC\UTC\k 39 2 comentários

Disclaimer: esse post é uma opinião muito pessoal de seu autor, e pode ser que os outros membros do blog não concordem.

Como eu já disse por aqui, eu fico bastante entusiasmado com a idéia de cursos abertos online e disponibilização de material em vídeo, como na iniciativa OpenCourseWare, por exemplo. E eu sou um usuário adicto desses materiais. Já devo ter ouvido as aulas de mais de uma dezena desses cursos, por diversão mesmo, em áreas muito diversas (história, estudos religiosos, biologia, antropologia…). Mas não comecei esse texto para falar desses cursos, mas para falar de algo que esses cursos me fizeram notar a respeito de uma diferença fundamental entre o ensino de física e o ensino em outras áreas do conhecimento, de forma particular, mas não restrita, nas ciências médicas e biológicas.

Para exemplificar o que quero dizer, vou me referir à terceira aula do curso de biologia geral dado na primavera de 2010, na Universidade da Califórnia em Berkeley, cujas aulas em vídeo e éudio estão disponíveis para download no site de webcasts da universidade (http://webcast.berkeley.edu). Em certo ponto dessa aula, a professora diz “e realmente nos últimos 5 ou 6 anos muita pesquisa foi feita para entender a estrutura interna e função do ribossomo, e eu vou mostrar para vocês uma imagem…” e passa a discorrer sobre assunto de pesquisa muito recente, sobre o qual ainda há dúvidas e questões em discussão. Cenas como essa são comuns em todos os cursos que ouvi. Assuntos de pesquisa são citados na sala de aula rotineiramente e discutidos nos trabalhos e dissertações que os alunos tem de entregar para ser avaliados. Isso me chocou. Me chocou como algo completamente alheio com a minha experiência de sala de aula, que acredito ser não muito diferente da experiência de todos os físicos formados no Brasil, e provavelmente no mundo todo. É inconcebível na nossa experiência que um professor de Física I (ou de Physics 101) entre na sala de aula e dê como exercício de casa a uma turma mista de dezenas e dezenas ingressantes de diversos cursos – engenharia, física, química, … – a leitura de um artigo de pesquisa publicado a menos de 10 anos. Nenhum assunto discutido em uma aula de física, mesmo nos últimos anos da faculdade, é mais recente do que a década de 40. Em compensação, poucos assuntos discutidos em uma aula de biologia celular são mais antigos que a década de 70, e muitos tem menos de 10 ou 15 anos de idade! E por que é assim?

Tudo bem, há uma série de explicações muito plausíveis para isso. Talvez a mais forte seja que os conceitos físicos e as ferramentas matemáticas usadas na pesquisa são muito mais avançados do que os que estão sendo estudados na graduação, e que é necessário um período longo de treinamento para sair da primeira aula sobre as leis de movimento de Newton e chegar na mecânica quântica, passando por todos aqueles passos intermediários. A maturação de um físico é um processo longo e lento, nessa visão. Vai da primeira aula de Física I até mais ou menos o meio do doutorado. A física é uma ciência mais antiga e madura, dizem os que defendem essa idéia, e um estudante de física tem que estudar toooodas essas coisas com detalhes, desde o nascimento da mecânica newtoniana até a mecânica quântica e suas aplicações mais elementares. Além disso, um ingressante em física ainda não foi exposto nem ao ferramental matemático básico para prosseguir aprendendo física – o cálculo, a algebra linear e etc…

Apesar de acreditar que há alguma verdade nisso, sinceramente acho que ela é exagerada e super-simplificada pela típica autosuficiência e arrogância dos físicos (eu me incluo nessa conta) e pela inércia do sistema educacional. Faz anos que é assim, foi assim que fizemos no passado, é assim que faremos no futuro porque é assim que se ensina física. E bem, veja só, é mais difícil aprender física, não é?

Não. Não é. Sinceramente, não é. Aprender biologia pra valer é tão difícil quanto aprender física. Ou mais! Pode ter um pouco menos de matemática, mas nas duas ou três primeiras aulas do curso introdutório para a graduação da UC Berkeley que assisti já há uma série de mecanismos celulares complicados, relações entre as organelas, estruturas moleculares complicadas, como as isomerias e as simetrias afetam a função das moléculas, e se o carbono alfa está assim, então a isomeria faz com que o poro da membrana nuclear fique assado… 😯 😯 😯

Não é fácil, definitivamente. E não é “coleção de selos”, é uma sequencia lógica de mecanismos e estruturas bem entendida até certo ponto. Eu não estou acompanhando direito.

Porque um ingressante de biologia está pronto para discutir a biologia molecular dos poros da membrana nuclear de maneira tão detalhada e um estudante de física não está pronto para discutir fenômenos críticos e transições de fase, ou entender, pelo menos num nível qualitativo, o que é decoerência, o que são teorias de campo conforme e porque a correspondência AdS/CFT é tão importante, quais são as alternativas para explicar energia escura, porque o grafeno é um material tão especial, porque é tão difícil ter materiais semicondutores que sejam ferromagnéticos, o que a física por trás de folding de proteínas tem a ver com a física de cristais magnéticos, quais são os melhores candidatos para física além do modelo padrão, como podemos detectar radiação Hawking?

E se tocamos nesse assunto, porque não ir mais fundo? Se os estudantes de física não chegam à metade do século passado, os estudantes do colegial param muito antes disso. A física que fingimos ensinar nas escolas tem pelo menos 150 anos de idade, e é absolutamente inútil para essas pessoas da forma como é ensinada, em todos os aspectos. Não estimulam curiosidade científica, não as ajudam a entender o ambiente tecnológico em que vivem, não fornecem ferramentas de trabalho úteis e nem as preparam para a universidade.

O ensino de Física está, em minha opinião, caduco em todos os níveis e precisando de urgente reforma. E quanto mais a pesquisa avança, mais urgente essa mudança se torna. Se queremos pessoas prontas para integrar os quadros de pesquisa, se queremos estudantes motivados e se queremos desenvolver o quanto antes o gosto pela pesquisa, precisamos forçar a fazer o que os biólogos fizeram de forma natural, e trazer a física da pesquisa de volta para as salas de aula.

Um pouco de propaganda…

terça-feira, 3 ago 2010; \31\UTC\UTC\k 31 Deixe um comentário

Bem, eu vou propagandear aqui outro blog que criei aqui no wordpress para falar principalmente sobre programação funcional, Haskell e as relações dessa linguagem com matemática e física. Como essa comunidade é bastante específica, escrever em português não atingiria muita gente então eu criei um blog para escrever sobre isso em inglês (broken english…). Além disso é um assunto bem distante daqui e então não faz muito sentido colocar no mesmo lugar.

De qualquer forma eu óbviamente não vou deixar de escrever aqui, e quando eu achar que tem algo desse assunto que seja suficientemente geral para caber aqui, vou postar aqui também, em português.

Enfim, para quem se interessar: http://randomagent.wordpress.com/ é o endereço do outro blog, onde já há um tutorial sobre monad transformers usando processos estocásticos como exemplo. 🙂

Categorias:Ars Physica
%d blogueiros gostam disto: