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

7 comentarios:

  1. Hola. He seguido todos los pasos, y aún así no puedo hacer funcionar Java con Prolog. El error que tengo es el siguiente

    /usr/lib/jvm/java-6-openjdk/bin/java: symbol lookup error: /usr/lib/swi-prolog/lib/i386/libjpl.so: undefined symbol: PL_is_initialised

    Estoy usando Ubuntu 11.04. Agradecería un poco de ayuda. Muchas Gracias.

    ResponderEliminar
  2. HOla, parece que hay un problema con la compilación del paquete 5.10 de prolog para ubuntu 11.04 64 que no permite el uso de la librería compartida. Puedes probar recompilando desde la fuente el paquete e swi-prolog-java teniendo en cuenta las instrucciones de:
    http://code.google.com/p/javanaproche/wiki/HowToJPL

    O puedes instalar los paquetes de maverick de la version 5.8 de swi-prolog. Los puedes descargar desde: https://launchpad.net/ubuntu/+source/swi-prolog/5.8.2-2/+build/1731578

    Yo use el segundo método y estoy trabajando sin problemas.

    ResponderEliminar
  3. Hola Christian, Acudo en tu ayuda, He leído millón veces tu blog. Y créelo que aun no lo he podido resolver. Tengo Ubuntu 11.04 32bits y prolog 5.10. Instale la versión de prolog 5.8 como mencionaste. y me sigue saliendo este mensaje.
    Exception in thread "main" java.lang.UnsatisfiedLinkError: no jpl in java.library.path

    Créelo ya hecho de todo y no funca. Incluso me contacte con los desarrolladores de Prolog y me supieron decir que si funciona la versión 5.10.

    Por favor dame una mano es algo urgente.

    Lo que pienso yo que estoy haciendo mal es la colocación de las variables de entorno.

    Te lo estaré eternamente agradecido.

    ResponderEliminar
  4. Crees que podrías conectarte a mi PC a través del Team Viewer y ver en donde esta mi error. No te tomaría mas de media hora. Por cierto en Windows si me funciona. Ahí coloque las variables de entorno y funco sin problemas.

    Gracias de antemano Christian.

    ResponderEliminar
  5. Genial, muchas gracias, sería excelente que el código estuviera completo, en fin, perfecto :D Gracias.

    ResponderEliminar
  6. este es el código que sigue justo cuando se corta el for al comienzo de la segunda imagen.
    //------------------------------------------------
    for(int i=0;i<ss4.length;i++){
    System.out.println("X = " + ss4[i].get("X"));
    }

    //----------------------------------------------

    System.out.println("each solution of " + t4);

    while(q4.hasMoreSolutions()){

    @SuppressWarnings("rawtypes")
    java.util.Hashtable s4 = q4.nextSolution();
    System.out.println("X = " + s4.get("X"));

    }

    //----------------------------------------------
    String t5 = "descendent_of(X,Y)";
    Query q5 = new Query(t5);

    System.out.println("each solution of " + t5);

    while(q5.hasMoreSolutions()){
    java.util.Hashtable s5= q5.nextSolution();
    System.out.println("X = "+ s5.get("X") + ",Y = " + s5.get("Y"));
    }

    ResponderEliminar
  7. Por cierto buen aporte, no sabes cuánto lo necesitaba :D

    ResponderEliminar