Saturday, July 29, 2006

Me voy de vacaciones

Y a la vuelta, novedades (una fusion con otro blog).

Wednesday, July 19, 2006

La informática también es una ciencia

La Informática es una gran ciencia. En contra de lo que podemos pensar como usuarios, es una disciplina bien estructurada, en ocasiones infinitamente mejor pensada que la arquitectura o la ingeniería civil. Y sin embargo, las casas apenas se caen y los sistemas informáticos apenas se sostienen.

La culpa, desde mi punto de vista, no la tiene la Informática sino el desempeño de la misma. ¿Quién quiere hacer un buen diseño de un software si los 40 días que necesitaría para la documentación y análisis del problema se los doy a los pobres becarios (físicos como yo muchos de ellos) para que programen casi a ciegas?

En otras palabras, la Informática es una ciencia, pero los informáticos (en general y sobre todo muchos intrusos de otros campos) son pobres ingenieros informáticos.

Esta reflexión no tiene mayor transcendencia (salvo la de una conversación en un bar) si no fuera por el decisivo papel que puede tener la informática en otras ciencias. Muchos físicos como yo dependemos de la misma para desarrollar nuestras teorías, contrastarlas y representar la información en la pantalla de un ordenador.

La cuestión es, ¿podemos aprovecharnos de la teoría que subyace a la Informática para hacer mejor nuestra ciencia? Mi respuesta es sí.

Os pondré un ejemplo (que desarrollaré otro día cuando os hable de mi proyecto de crear una librería para integrar [casi] cualquier problema de la Física basado en ecuaciones diferenciales).

Queremos estudiar un cierto modelo que hemos propuesto analíticamente para explicar el fenómeno F. El modelo consiste en una ecuación en derivadas parciales para el observable H que depende del tiempo "t" y de la posición "x" (n-dimensional). ¿Qué hacemos?

1) Cogemos un programa que hayamos desarrollado para un problema similar (en FORTRAN o C) y lo adaptamos al nuevo problema
2) Creamos un nuevo programa que es bastante mejor que los anteriores porque corrige algunos fallos que tenían estos o simplemente nos resulta más fácil de manipular o entender.
3) Conseguimos que alguien nos haga el programa.

La solución 3) es genial, sólo que a veces las cosas no le salen a nuestro colega y nos cuesta un horror entender su código y poder ayudarle.

La solución 2) es la que adoptamos la mayor parte de las veces, máxime teniendo en cuenta que ya no entendemos los códigos que hicimos para otros problemas similares o simplemente no sabríamos cómo modificarlos fácilmente.

La solución 1) está muy bien, sólo que hay que tocar en "N" sitios para que el código al final nos dé el resultado esperado.

¿Pero realmente qué hacen todos nuestros programas?

1) Empieza el programa principal. Se declaran las variables, los parámetros, algunas funciones o subrutinas auxiliares...
2) Se leen datos de un fichero (o de la línea de comandos) para definir los parámetros del problema. Algunos de estos parámetros son del modelo y otros de la simulación (intervalo de tiempo, precisión, número de promedios, semilla del generador de números aleatorios, ...)
3) Se fija la condición inicial, se crean los ficheros de salida, ...
4) Empieza la "simulación" o integración numérica por el método X y periódicamente guardamos el valor de un observable (la media, la varianza, ...) en un fichero.
5) Se post-procesan los resultados de la simulación y ADIOS CHARLIE.

Los que trabajamos con el numérico hacemos esto infinidad de veces.

Otro ejemplo son las simulaciones de Monte Carlo, o autómatas celulares, o simulaciones basadas en agentes (para problemas sociales o biológicos, ...)

La Informática tiene soluciones más serias para estos problemas. Las llaman Metodologías. En particular hay una que causa furor desde hace años y que no está suficientemente explotada por los científicos de otras áreas (como siempre, hablo en términos generales desde mi reducida perspectiva): la orientación a objetos.

La orientación a objetos trabaja con abstracciones, sin importar los detalles particulares del problema. Así, en el ejemplo que puse antes, lo que importa es que trabajamos con parámetros, campos, números aleatorios, ecuaciones, observables, ...

Bien, definamos objetos para todas estas abstracciones y ya podremos reutilizar de manera transparente y eficiente la mayor parte de nuestro código sin tener que retocar a mano todo el mismo.

Por ejemplo, un código como el que describía anteriormente podría ser así en C++:

#include

main()
{
[...]
fichero >> ParametrosDeLaSimulación;
fichero >> ParametrosDelModelo;
fichero >> ListaDeObservables;
fichero >> Ecuaciones;
algoritmo.set("RungeKutta4");
simulador.crea(Ecuaciones,algoritmo,ParametrosDeLaSimulacion,ParametrosDelModelo,
ListaDeObservables);
simulador.postprocesayguarda(Observables);
}

Esto hay que diseñarlo bien, pero una vez hecho, qué más da que las ecuaciones modelen la erosión de una superficie o el crecimiento de un tumor (cuña publicitaria ;-) ): la estructura es la misma.

En fin, mi conlcusión es:
* Estudiemos Orientación a Objetos
* Hagamos códigos robustos, extensibles, legibles, eficientes y versátiles
* Una vez hecho esto: centrémonos en la ciencia no en la informática.

Otro día hablaré de este último punto, pero lanzo una pregunta ¿no tenéis la impresión de que a veces trabajamos sin un gran proyecto a largo plazo? Es decir, está muy bien el tipo de problemas que estudiamos (si no fuese así tampoco lo admitiríamos) pero, ¿no aspiramos a un conocimiento de mayor nivel? ¿Resolvemos problemas o PROBLEMAS?

En fin, que ya me va entrando hambre.

Esta vez, espero vuestros comentarios.

Tuesday, July 18, 2006

Espeluznante

He visto esta noticia que me ha dejado ciertamente perplejo.

Así que, a partir de ahora no permito comentarios anónimos.

Tuesday, July 11, 2006

Más sobre creación de imágenes, esta vez en color

En mi primer post (bueno el segundo) os conté cómo crear una imagen bidimensional a partir de un fichero de datos. En esta entrega os contaré como hacer lo mismo con color.

Para empezar, ya no crearemos un fichero pnm sino uno de tipo ppm. La diferencia reside en que los primeros cuantifican el color con un número entre 0 y 65535 y los segundos con una terna de números entre 0 y 255 que representan la cantidad de rojo verde y azul que contiene la imagen.
Para que entendáis mejor el código voy a crear un código intermedio que hace lo mismo que el del post anterior pero en el nuevo formato.

Así, el código en custión sería



#!/bin/bash

if [ $# -ne 3 ]; then
echo "Sintaxis: $0 Nx Ny fichero_de_entrada "
exit
fi

awk '
BEGIN{max=-100000000; min=100000000;}
{
for (i=1;i<=NF;i=i+1){ if (max<$i) max=$i; if(min>$i) min=$i;}
}
END{print max,min}' $3 | awk -v Nx=$1 -v Ny=$2 '
BEGIN{print "P3\n#\n\n" Nx,Ny "\n255 255 255"}
NR==1 {
max=$1;
min=$2;
}
{
for(i=1;i<=NF;i=i+1) {
val=int(($i-min)*255/(max-min))
print val,val,val
}
}' - $3 >$3.ppm




Fijaos en la diferencias:
1) El tipo de archivo no es "P2" sino "P3".
2) En lugar de incluir una única escala (65535) incluimos tres (255 255 255).
3) Por cada pixel imprimo tres números (con el comando print val, val, val)

¿Qué necesitamos para crear una imagen en color? Pues muy fácil, una paleta. Las paletas permiten hacer una mapping entre un subconjunto de los números reales (entre min y max) a un espacio vectorial de tres dimensiones de enteros (entre 0 y 255).

Existen muchas paletas. Yo he usado una que cree hace siglos para una aplicación en basic que hice en el colegio. La versión awk sería la siguiente:



#!/bin/bash

if [ $# -ne 3 ]; then
echo "Sintaxis: $0 Nx Ny fichero_de_entrada "
exit
fi

awk '
BEGIN{max=-100000000; min=100000000;}
{
for (i=1;i<=NF;i=i+1){if (max<$i) max=$i; if(min>$i) min=$i;}
}
END{print max,min}' $3 | awk -v Nx=$1 -v Ny=$2 '
BEGIN{
for(i=0;i<128;i++) {
b[i]=int(255-2*i*i/128); g[i]=int(255-2*(128-i)*(128-i)/128); r[i]=0;}
for(i=0;i<128;i++) {
b[i+128]=0; g[i+128]=int(255-2*(i)*(i)/128); r[i+128]=int(255-2*(128-i)*(128-i)/128); }

for(i=0;i<=255;i++) {
if(r[i]<0) r[i]=0; if(g[i]<0) g[i]=0; if(b[i]<0) b[i]=0;
if(r[i]>255) r[i]=255; if(g[i]>255) g[i]=255; if(b[i]>255) b[i]=255;}

print "P3\n#\n\n" Nx,Ny "\n255 255 255"
}
NR==1 {
max=$1;
min=$2;
}
{
for(i=1;i<=NF;i=i+1) {
val=int(($i-min)*255/(max-min))
print r[val],g[val],b[val]
}
}' - $3 >$3.ppm




La definición de la paleta está incluida en los bucles

for(i=0;i<128;i++) {
b[i]=int(255-2*i*i/128); g[i]=int(255-2*(128-i)*(128-i)/128); r[i]=0;}
for(i=0;i<128;i++) {
b[i+128]=0; g[i+128]=int(255-2*(i)*(i)/128); r[i+128]=int(255-2*(128-i)*(128-i)/128); }


El bucle que aparece a continuación de estas líneas es para comprobar que no hay errores de rango.

Si queréis crear otra paleta, sólo teneís que definir las matrices r[], g[] y b[]. MATLAB tienes decenas de paletas definidas que probablemente se puedan exportar.

Para que veáis un ejemplo os incluyo una imagen de unas simulaciones de un modelo de Crecimiento de Depósitos de Vapor (CVD).

Selección natural en Física

Thursday, July 06, 2006

Linux en el top manta

No me resisto a poner este link


Wednesday, July 05, 2006

Vim, ese semidiós (primera parte)

Hoy voy a hablar de vim (la versión mejorada de vi). vim tiene todo lo bueno de vi, pero además permite una serie de extensiones, plugins y macros que quitan el aliento. En otra ocasión os hablaré de los plugins y os recomendaré alguno. Mientras podéis disfrutar de todo sobre vim en el enlace

http://www.vim.org

En este post os hablaré del fichero de configuración .vimrc que se encuentra en vuestro directorio $HOME

Este fichero permite incluir una serie parámetros y opciones que se cargan en vim en el momento de arranque.

A continuación os detallo algunas líneas de mi fichero .vimrc que os
pueden ser de utilidad
" Los comentarios van precedidos por unas comillas
" La siguiente línea cambia el tamaño por defecto del tabulador a 3
set tabstop=3

" mantiene 50 líneas de historia de comandos en una sesión vim
set history=50
Y ahora mi parte favorita, los "mapeos" de teclas a comandos.

" Los tres siguientes permite usar el comando externo 'par' que
" viene con casi todas las distribuciones linux (salvo Suse) e incluso
" con cygwin y que permite manipular párrafos de texto
" El siguiente simplemente toma un párrafo (considerando párrafo hasta
" las siguiente línea vacía) y lo ajusta a 78 columnas simplemente pulsando
" F3
map <F3> <Esc>!}par -w78 <CR>
" El siguiente hace lo mismo pero para un selección hecha en
" modo visual (con el comando v), de ahí la v de 'vmap'
vmap <F3> !par -w78 <CR>
" Por último, pulsando F4 ajusta el texto a 78 columnas indentando por
" los dos extremos (añadiendo espacios si fuese necesario)
map <F4> !}par -j1 -w78 <CR>

" imap hace referencia a comandos en modo 'insertar'. El siguiente
" comando ayuda a escribir textos en LaTex. Si escribes la palabra
" itemize y pulsas (en modo insertar) F4 te crea el begin y end
" correspondientes.
imap <F4> <Esc>bi\begin{<Esc>$a}<Esc>yypwdwiend<Esc>O

" Y ya que estamos con Latex, aquí tenéis algo cómodo
" F5 guarda el fichero actual y lo compila
map <F5> :w!<CR>:!latex %<CR><CR> <CR>
" F6 invoca al comando xdvi
map <F6> :!xdvi %<.dvi&<CR><CR>
" F7 crea el postscript correspondiente (en compatibilidad PDF) y llama
" al programa "gv"
map <F7> :!dvips -P pdf -G0 %<.dvi >& /dev/null <CR><CR>:!gv %<.ps &<CR><CR>
" Por último, F8 crea un pdf y llama al comando xpdf
map <F8> :!ps2pdf %<.ps<CR>:!xpdf -z page %<.pdf &<CR><CR>
Para finalizar, os hablaré de los pliegues o 'folds'. Son agrupaciones de varias líneas en una única línea que se despliega con un comando. Para más información sobre los pliegues podeís poner (dentro de vim) :help folds.
Yo uso los pliegues cuando escribo un código en C++ o un documento en LaTex muy grande. Para C++, lo que me interesa es que todas las estructuras, clases y subrutinas se compacten. De este modo un código con 6 clases, 14 funciones y la función main, se reduce a la parte de los includes, las variables globables y 21 pliegues, lo cual cabe casi en la ventana de edición por lo que puedo echar un vistazo muy rápido al código completo.

Para manejar los pliegues en un código C++, bastaría con añadir a .vimrc:


map F za
map <S-F12> :set foldmarker=\{,\}<CR> :set foldmethod=marker<CR>


El primer mapeo permite conmutar entre abierto y cerrado cuando estamos situados sobre un pliegue pulsado F (en modo comando, se entiende). La segunda línea somplemente crea los pliegues al pulsar shift-F12.

Para LaTex, podríamos hacer, por ejemplo:

map <S-F12> :set foldmarker=\\begin,\\end<CR> :set foldmethod=marker<CR>