viernes, 26 de febrero de 2010

JPL - Uniendo Prolog y Java en Linux

JPL es una interfaz que permite comunicar a Java con Prolog y viceversa. Esta interfaz se puede descargar como una librería adicional de la implementación ampliamente conocida de prolog: Swi-prolog. Existen en internet documentos que explican como hacer funcionar dicha libreria e incluso dan ejemplos, sin embargo, en algunos casos no funcionan y salen errores extraños que no brindan pistas sobre lo que esta sucediendo.

La dificultad principal radica en que no solamente tenemos que agregar al CLASSPATH una o varias librerías *.jar sino que se requieren librerías del sistema para que todo trabaje correctamente.

Entorno:
***********************************************
SO: Ubuntu karmic koala (9.10)
Java: java-6-sun
IDE: Eclipse Galileo (desde donde hice la prueba)
***********************************************

Desde el manejador de paquetes synaptic descargamos swi-prolog y swi-prolog-jpl. Generalmente no es necesario descargar el código fuente y hacer una compilación manual.
Una vez descargados e instalados dichos paquetes, tendremos en el directorio /usr/lib/swi-prolog/ los archivos que necesitamos para trabajar.

Estos son los archivos clave que hay que tener en cuenta:

En /usr/lib/swi-prolog/lib esta el archivo jpl.jar
En /usr/lib/swi-prolog/lib/i386 esta el archivo libjpl.so


Ahora vamos a poner a funcionar el ejemplo que trae swi-prolog. Este es el archivo prolog:

*****************************family.pl******************************
child_of(joe, ralf).
child_of(mary, joe).
child_of(steve, joe).
descendent_of(X, Y) :-
child_of(X, Y).
descendent_of(X, Y) :-
child_of(Z, Y),
descendent_of(X, Z).
*******************************************************************

Y este el de Java:
*******************************Family.java**************************
package jpl;

public class Family {

public static void main( String argv[] )
{
String t1 = "consult('family.pl')";
Query q1 = new Query(t1);
System.out.println( t1 + " " + (q1.hasSolution() ? "succeeded" : "failed") );
//--------------------------------------------------
String t2 = "child_of(joe, ralf)";
Query q2 = new Query(t2);
System.out.println( t2 + " is " + (q2.hasSolution() ? "provable" : "not provable") );
//--------------------------------------------------
String t3 = "descendent_of(steve, ralf)";
Query q3 = new Query(t3);
System.out.println( t3 + " is " +(q3.hasSolution() ? "provable" : "not provable") );
String t4 = "descendent_of(X, ralf)";
//--------------------------------------------------
Query q4 = new Query(t4);
System.out.println( "first solution of " + t4 + ": X = " +
q4.oneSolution().get("X"));
//--------------------------------------------------
java.util.Hashtable[] ss4 = q4.allSolutions();
System.out.println( "all solutions of " + t4);

for ( int i=0 ; iAhora crearemos en Eclipe un proyecto que nos permita verificar el funcionamiento de la librería.

Creamos un proyecto java llamado familyJPL, y creamos el paquete jpl. Luego creamos el archivo Family.java descrito previamente. En el directorio raíz del proyecto creamos el archivo family.pl y agregamos la librería jpl.jar. En este momento el proyecto debe lucir como la imagen.

Ahora editemos las opciones de ejecución (por ejemplo dando click derecho sobre Family.java, seleccionamos la opción Run as y posteriormente Run Configuration). En el tab de arguments en el campo VMArguments copiamos la siguiente linea:

-Djava.library.path=/usr/lib/swi-prolog/lib/i386/

y en el tab enviroment creamos una nueva variable que nombramos SWI_HOME_DIR y le damos el valor de /usr/lib/swi-prolog/. Por supuesto los directorios deben ser ajustados con los valores propios de su instalación. Los valores que suministro aqui son las rutas por defecto donde se instala SWI-PROLOG y JAVA.

Ahora si todo quedo listo y podemos ejecutar el proyecto y disfrutar del resultado.

POSIBLES ERRORES

[FATAL ERROR: Could not find system resources]
  • Esto sucede cuando al ejecutar el programa java no se conoce la ubicación del interprete de prolog. Esto se soluciona definiendo la variable de ambiente SWI_HOME_DIR antes de iniciar eclipse, en los parametros de ejecución en el tab enviroment o programaticamente mediante la instrucción:
  • putenv("SWI_HOME_DIR=/usr/lib/swi-prolog/");
  • Puedes consultar sobre este error en http://www.swi-prolog.org/FAQ/FindResources.html
Exception in thread "main" java.lang.UnsatisfiedLinkError: no jpl in java.library.path

Esto sucede cuando no se ha definido correctamente la ruta donde se encuentra la librería del sistema de jpl. Esto se soluciona agragando la opción de ejecución -Djava.library.path=/usr/lib/swi-prolog/lib/i386/ (o el directorio donde tengas el archivo libjpl.so)


OTROS LINKS ÚTILES:
Documento oficial de Swi-prolog de instalación de JPL: http://www.swi-prolog.org/packages/jpl/installation.html
JPL 3.0 API Reference: http://www.swi-prolog.org/packages/jpl/java_api/javadoc/index.html
Java/Prolog interface (SWI Prolog JPL) up running! http://saml.rilspace.com/content/javaprolog-interface-swi-prolog-jpl-up-running