Inteligencia Artificial y Soft Computing. Teoría y Aplicaciones

Hace unos días (el 25 de Abril para ser exactos) llegué a uno de los checkpoints que hay en mi ruta: la defensa de mi Proyecto Final Máster. Como ocurre en estos casos, los nervios hicieron que no todo fuese tan bien como debería, pero aún así fue mejor de lo esperado. Es un pasito más en mis estudios, lo cual me hace feliz.

El proyecto trata del Soft-Computing, una rama que pertenece a la Inteligencia Artificial, y que trata el conocimiento con una aproximación un tanto diferente a la Inteligencia Artificial clásica. En esta última, el conocimiento se suele concebir primero como abstracción, y luego se intenta representar esta abstracción (a esto se le suele llamar aproximación Top-Down del conocimiento). Las técnicas del Soft-Computing se caracterizan precisamente por representar el conocimiento de forma subsimbólica, es decir, modelando los componentes básicos del conocimiento para representar un conocimiento que «emerge» de sus interconexiones (se puede ver muy fácil si se piensa en las neuronas como componente y en el cerebro como el resultado, por eso se le suele llamar aproximación Bottom-Up).

El caso es que aquí tenéis el enlace para todos aquellos que quieran leerlo, ojearlo o criticarlo: thesis.pdf. Y en esto último me gustaría incidir. El libro del proyecto fue concebido como punto de entrada al Soft-Computing, así que si alguien lo lee, agradezco cualquier tipo de feedback.

Muchas gracias y ¡Un saludo a todos!

clang: error: unknown argument: ‘-mno-fused-madd’

Estos días me he venido pegando con un error al instalar algunas librerías en una máquina con OS X 10.9 instalado. Ahora mismo me acaba de pasar al intentar instalar PyGame en un entorno virtual, así que aprovecho y os pongo la receta según lo voy haciendo.

Si al instalar una librería (e.g. pygame) a golpe de pip o easy_install da el siguiente error:

$ pip install hg+http://bitbucket.org/pygame/pygame
Downloading/unpacking hg+http://bitbucket.org/pygame/pygame
...
...
...
clang: error: unknown argument: '-mno-fused-madd' [-Wunused-command-line-argument-hard-error-in-future]

clang: note: this will be a hard error (cannot be downgraded to a warning) in the future

error: command 'cc' failed with exit status 1

----------------------------------------
Cleaning up...

Es decir, lo que viene a ser un «ZASCA!!», con exportar las siguientes variables de entorno la instalación funcionará:

$ export CPPFLAGS=-Qunused-arguments
$ export CFLAGS=-Qunused-arguments
$ pip install hg+http://bitbucket.org/pygame/pygame
Downloading/unpacking hg+http://bitbucket.org/pygame/pygame
...
...
...
Successfully installed pygame
Cleaning up...

Y todos felices. Según me ha parecido entender, en una de las últimas actualizaciones (creo que en Marzo de este año), el compilador de C (clang) cuando encuentra una flag desconocida lanza un error (en lugar de un warning como hacía antes). La flag -mno-fused-madd es de GCC y debe ser que a clang no le mola.

Que paséis buen fin de semana!

Exportar repositorio con git archive

Acabamos de terminar blazaid y yo la mudanza del dominio, así que me ha picado el gusanillo de volver por estos lares para escribir una nueva entrada. Esta vez para un howto rapidito sobre git.

A veces necesitamos exportar un proyecto de git para subir a un servidor, pero no queremos clonar el repositorio con «git clone», ya que tendremos el árbol de directorios, incluido .git y cosas que no querremos subir. Una opción es copiar únicamente los directorios y ficheros que queramos a una nueva ubicación, y listo. Pero si lo hacemos más de tres veces empezaremos a murmurar cosas como «tu madre era un troll» a la pantalla. Y no es plan… Así que para automatizar un poco, obviando sistemas de Integración Continua, mucho más-mejores y más mega-profesionales, podemos usar el comando git archive.

Todo vino con una búsqueda en google similar a «svn export in git«. En SVN era tan sencillo como el comando anterior, así que siendo git mucho más evolucionado, con exoesqueleto de adamantio y todo, tenía que poderse hacer. No me equivocaba. Un par de visitas a stackoverflow y ya estaba creándome todos los scripts en bash para ello.

Desde el path donde tengamos el repositorio que queramos exportar ejecutamos:


# Formato tar.gz
git archive HEAD | gzip > /path/to/export/project.tar.gz

# O en zip
git archive --format zip --output /path/to/export/project.zip HEAD

Es importante haber hecho commit de todos los ficheros que queramos, puesto que en este caso nos subirá lo que esté en HEAD (se puede poner master / devel o la rama que uséis vosotros). Con esto tendremos un fichero comprimido que podremos copiar donde queramos.

Esto nos comprimirá todo el contenido del proyecto, obviando el directorio .git. Tampoco es mucho avance.

Para elegir qué más cosas quitar de la exportación, podemos hacer uso del fichero .gitattributes, que crearemos en el raíz del proyecto. El mío tiene un aspecto parecido al siguiente:

# Used to remove files from deployment using `git archive`

# Git Files
.gitignore export-ignore
.gitattributes export-ignore

Thumbs.db export-ignore
project.tar.gz export-ignore

# Directories
_docs export-ignore
_scripts export-ignore

# General text files
*README.txt export-ignore
*LICENSE.txt export-ignore
COPYRIGHT.txt export-ignore
CHANGELOG.txt export-ignore

Esto hará que se excluyan las carpetas /_docs y todos los archivos que no queramos, como el propio .gitattributes o los famosos .gitignore, dejándonos un proyecto limpio y listo para poder subirse a producción sin mucho problema.

¡Feliz semana!

Robocode – Buscando el robot de combate definitivo

El vídeo que os traigo hoy va de Robocode, un juego de programación cuyo objetivo es construir robots que acaben con otros robots. Simple y sencillo. Es como una versión cojo-evolucionada del Core War, pero en lugar de vírus, luchan tanques, en lugar de ensamblador endemoniado, Java o .NET y en lugar de ocupar la memoria del oponente, es destruir su tanque.

Es decir, que se parece como un huevo a una castaña, pero no deja de ser un juego de programación :).

Los autores (o al menos uno de ellos) han puesto un enlace al paper (http://www.jonnielsen.net/RoboReportOfficial.pdf). Usan dos controladores, uno basado en una red neuronal entrenada con backtracking (el de la torreta) y otro basado en una red neuronal evolucionada (el de movimiento). La pena es que, según los resultados, sólo puede vencer a oponentes fáciles. Los mejores siguen ganando. Aún así, tiempo al tiempo. Yo confío en las máquinas :D.

Buenas noches!

Evolución de equipos de fútbol

La gran mayoría de las personas que me conocen saben que me encantan los días de fútbol porque puedes salir a la calle e ir al cine y estar prácticamente sólo. Sin embargo, cuando se trata de softbots, la cosa cambia :D.

El vídeo que os presento aquí es una simulación de una evolución de equipos de fútbol a golpe de hacer evolucionar redes neuronales.

El vídeo explica muy someramente cuáles son los parámetros de aprendizaje, pero para los que conozcan un poco del tema lo dejan bastante claro. Lo divertido viene a partir del segundo 28», donde se van presentando partidos con distintas generaciones.

Para los que tengan ganas de conocer un poco más sobre su funcionamiento, el paper se encuentra en esta dirección: http://downloads.hindawi.com/journals/jr/2010/841286.pdf. Espero no meterme en un lío. De todas formas, si tengo yo el enlace en mis bookmarks no debe ser muy complicado encontrarlo :).

Que lo disfrutéis!

Cuando dos robots se conocen

Si Turing levantase la cabeza…

El vídeo que os presento aquí es el resultado de poner a hablar dos instancias de cleverbot (www.cleverbot.com) hablando una con la otra. No tiene desperdicio:

Por cierto, me quedo con el momento epic-creepy del minuto ~2:48 (a no ser que yo me lo haya inventado y en realidad digan otra cosa)

him – Hahaha
her – What’s so funny?
him – You are
her – why am I funny?
him – Because you are
her – Why are you laughing?
him – I need blood

De las mejores declaraciones de amor de la historia. Saludos!

Instalar Jira tras nginx en un subdominio (Debian 7)

Bueno, digo debian pero bien vale cualquier distribución basada en ésta.

Hace ya algún tiempo se publicó en este blog un post largo y detallado sobre como instalar Confluence. Desde entonces la instalación ha cambiado MUCHO. De hecho, ayer instalé un Jira y un Confluence ejecutando directamente el fichero descargado (marvelous!).

La receta es la siguiente. Lo primero, vamos a suponer que poseemos un dominio (megacorp.com) y hemos apuntado el subdominio (jira.megacorp.com) a una máquina con un Debian recién instalado. Lo primero que debemos hacer es instalar un gestor de bases de datos (en nuestro caso MySQL), nginx y la máquina virtual de Java, así que como root ejecutaremos lo siguiente:

apt-get install openjdk-6-jre nginx-full mysql-server

Una vez instalados los paquetes, crearemos una base de datos para nuestro Jira con su propio usuario para que no haya problemas. Para ello, entraremos en la consola de MySQL (mysql -u root -p) y ejecutaremos los siguientes comandos:

CREATE DATABASE jira CHARACTER SET UTF8 COLLATE utf8_unicode_ci;
GRANT ALL on jira.* TO 'jira_user'@'localhost' IDENTIFIED BY 'powerpass';
FLUSH PRIVILEGES;
EXIT

Y la base de datos ya está. Ahora pasaremos a instalar Jira propiamente dicho. Para ello descargaremos la última versión (en nuestro caso la versión de 64 bits para Linux) y lo ejecutaremos, instalándolo como servicio para que, cuando se reinicie la máquina, se inicie también Jira.

$ wget http://www.atlassian.com/software/jira/downloads/binary/atlassian-jira-6.2-x64.bin
$ chmod u+x atlassian-jira-6.2-x64.bin
$ ./atlassian-jira-6.2-x64.bin

En el proceso, lo suyo es elegir las opciones que más nos convengan. Una vez finalizado, como hemos usado MySQL como gestor de bases de datos, deberemos bajarnos el driver de MySQL (que no viene incluido por temas de licencias en el paquete de Jira). Para ello, wget te elijo a ti!

$ wget http://dev.mysql.com/get/Downloads/Connector-J/mysql-connector-java-5.1.29.tar.gz
$ tar -zxvf mysql-connector-java-5.1.29.tar.gz
$ cp mysql-connector-java-5.1.29/mysql-connector-java-5.1.29-bin.jar /opt/atlassian/jira/atlassian-jira/WEB-INF/lib/

En este momento tenemos corriendo Jira en el puerto 8080 (si no hemos cambiado nada en la instalación). Ahora, lo que queremos es ponerlo bajo nuestro subdominio. Aquí es donde entra nginx al rescate. Primero crearemos un nuevo fichero de configuración:

$ touch /etc/nginx/sites-available/jira
$ ln -s /etc/nginx/sites-available/jira /etc/nginx/sites-enabled/jira

Y en él escribiremos la siguiente configuración:

server {
	listen 80;
	server_name jira.megacorp.com;

	location / {
		proxy_set_header X-Forwarded-Host $host;
		proxy_set_header X-Forwarded-Server $host;
		proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
		proxy_pass http://localhost:8080/;
		proxy_redirect off;
	}
}

Sólo nos queda un último cambio, esta vez en la configuración del servidor Tomcat que viene empotrado en Jira. Para ello, abriremos el fichero server.xml, el cual se encontrará en la ruta /opt/atlassian/jira/conf/server.xml si se ha elegido el valor por defecto y cambiaremos el conector del puerto 80 para que tenga este aspecto:

<connector port="8080"
           maxThreads="150"
           minSpareThreads="25"
           connectionTimeout="20000"
           scheme="http" proxyName="jira.megacorp.com" proxyPort="80"
           enableLookups="false"
           maxHttpHeaderSize="8192"
           protocol="HTTP/1.1"
           useBodyEncodingForURI="true"
           redirectPort="8443"
           acceptCount="100"
           disableUploadTimeout="true">
</connector>

Realmente ha sido modificado únicamente con la línea scheme="http" proxyName="jira.megacorp.com" proxyPort="80". De hecho, en la propia definición del conector viene una línea vacía en el lugar donde la hemos instalado nosotros.

Para terminar, reiniciaremos Jira y nginx para que hagan efecto los cambios realizados de la siguiente forma:

$ service jira stop && service jira start
$ service nginx restart

Y arreando. Si accedemos con el navegador a la url jira.megacorp.com tendremos el menú para instalar Jira. Es un wizard fácil y bien explicado. Destacar que al seleccionar la base de datos, deberemos especificar el usuario y la contraseña que hemos usado antes (en nuestro caso jira_user< code> y powerpass) y, muy importante, la cadena useUnicode=true&characterEncoding=utf8 en la query de conexión.

Espero que os vaya bien. Cualquier duda, ya sabéis, a comentar!

Por cierto! En el post de que antes enlacé, David Bonilla me apuntó que no era necesario instalar una JDK para correr Jira o Confluence. Por eso en este caso he instalado la jre. Sin embargo, en aquel entonces la máquina donde instalaba el confluence también llevaba un Jira y un Bamboo. Este último se encargaba de la integración continua de los proyectos con los que trabajábamos, principalmente con Java, y a la hora de lanzar una tarea, o teníamos el JDK o nos fallaba. Sólo quería dejaros la nota por si acaso. Más saludos!

export PS1 con colores no respeta el salto de línea

Muy buenas a todos,

Hoy me he levantado inspirado y he querido que la línea de comandos de algunas de las máquinas con las que trabajo tengan colorines adorables del estilo [EEPGLEECYCG], lo cual no es ningún nombre de primigenio ni de nada por el estilo, es símplemente el acrónimo para la expresión Esto Es Producción, Gañán, Los Experimentos En Casa Y Con Gaseosa.

Por ello, he decidido poner en estas máquinas el siguiente esquema:

[PROD] root@goku:~#

Para lograr este prompt, he cambiado la variable de sistema PS1 por la siguiente:

$ export PS1='e[0;31m[PROD]e[m e[0;32m${debian_chroot:+($debian_chroot)}u@h:w$e[m ';

Al margen de lo que quiere decir cada cosa (si estáis interesados, os hago una descripción en otro post) resulta que esta expresión en principio correcta causaba que los saltos de línea no se respetasen, y que todo lo escrito, en el momento que llegaba a la columna 80 producía un retorno de carro sin salto de línea. Lo más gracioso es que obviaba completamente la configuración de terminal. Por muy larga que fuese la línea configurada para el terminal, en la posición 80 volvía a la posición 0 :D.

La solución (porque la razón aún no he sido capaz de encontrarla) es poner alrededor de los caracteres no imprimibles los comandos [ y ]. Aún estoy buscando el por qué de esto, pero la nueva expresión queda como sigue:

$ export PS1='[e[0;31m[PROD]e[m e[0;32m${debian_chroot:+($debian_chroot)}u@h:w$e[m] ';

Establecerlo en cada sesión es lo de menos. O bien se pone en /etc/profile para que lo tengan todos los usuarios, o bien en el .bash_profile o .bashrc del usuario al que se le quiera modificar.

Si os ayuda, me alegro. Saludos a todos!

Python, los floats y el ==

Algo en lo que siempre acabo metiendo la pata es a la hora de comparar floats. Es como la división entera, que siempre está ahí, para hacer aparecer el error cuando menos te lo esperas.

No conozco ningún lenguaje que no lo haga, pero a la hora de comparar un par de números, como alguno de ellos sea un número de coma flotante, no hay que hacer uso del == (a no ser que de verdad queramos, pero a mí nunca se me ha dado el caso).

Por una serie de problemas que no vienen al caso (muchas operaciones son aproximaciones del valor real), cuando queremos comparar dos números de este tipo siempre tenemos que realizar dos pasos:

  1. Elegir precisión (un valor pequeño para definir el intervalo de comparación, llamémoslo «e»)
  2. Comprobar que la diferencia entre los dos valores cae en el intervalo (-e, e). Si sí, son iguales y si no, pues no.

A continuación os paso los fuentes, aunque vais a necesitar un tiempo para asimilarlos porque el flujo es muy complicado de seguir.

def feq(x, y, e=0.00001):
  return abs(x - y) >= e

Feliz noche del lunes!

Restaurar Android y la verificación en dos pasos de Google

204px-Android_Update_ScreenComo buenos programadores deberíamos probar nuestro código, ya sea con pruebas unitarias, tests varios, a mano, o como queramos. Y para probar bien hay que probar los límites. Muchos programadores mediocres testean su código en los puntos intermedios: es decir, cuando una lista está parcialmente llena, cuando hay datos, cuando la configuración es correcta, cuando todo va como la seda… Lo que comúnmente se conoce como: lo que ve la suegra. Pero los buenos programadores van a los extremos. ¿Qué pasa si falta el fichero? ¿Qué sucede si el resultado que me devuelve está vacío? ¿Cómo se comporta con una base de datos sin datos? ¿Y si intento acceder si estar correctamente autenticado?

Pues ahora mismo estoy con la sensación de que alguien no ha hecho esas pruebas en Google. Estoy restaurando mi móvil Android, ya que haciendo pruebas a veces le meto mucha porquería. Tengo activada la verificación de cuenta en dos pasos que, primero te pide la contraseña y, si es correcta, envía un código al móvil para poder hacer login. Pero ¿y si lo que estoy restaurando es el mismo móvil? Meeeeeeeeeeeeeec!

¿Cómo voy a recibir el código si lo primero que hace Android es pedirme que inicie sesión en Google? Muy avispados. Tampoco aparece la notificación, ni tengo acceso al menú de programas porque ¡Estoy en la configuración inicial! Fantabuloso…

¿La solución? Hacer la configuración inicial parcialmente hasta que envíe el código. Cuando no podamos seguir, salimos y cuando nos pregunte si tenemos una cuenta de Google decirle que no, obviar la integración del dispositivo con Google y finalizar sin ninguna cuenta configurada. Entonces nos llegará la notificación con el código y ¡Tendremos que repetir todo de nuevo!

No sé, me resisto a pensar que en Google no prueben los extremos, así que pensaré que la torpe soy yo.
Que conste que a la hora de publicar esto ya tengo el móvil instalado, pero habiendo hecho esa chapuza de la que he hablado. ¿Alguien tiene una solución menos mala? Mi reino por algo menos cutre. Y quitar la verificación por código no es una opción viable para mí.