Google
 

domingo, 27 de abril de 2008

Programacion Logica : swi-prolog , Interfaces

Este articulo va destinado para las personas que tienen nociones básicas en programacion lógica o han manejado otro entorno programacion logica diferente al swi-prolog ejemplo visual prolog etc, Pero creo que no es tan dificil de entender lo que se les mencionara a continuacion. Lo ideal es que dado unas pequeñas nociones y funciones puedan utilizar la ayuda o demás herramientas para lograr un mejor entendimiento de todo lo que se mencionara a continuación Primeros pasos en swi-prolog en el blog de Jorge Valverde Revaza.



  1. Manejar Entorno de trabajo:
    Para esto abrir swi-Prolog aparecerá algo así , para tener un editor de programación lo único que debemos hacer es seleccionar de los botones de arriba Settings - User init file.. y nos aparecerá una nueva ventana cerramos la ventana y ahora si procedemos a file - New para crear un nuevo proyecto (la operación anterior algunos utilizan emacs.) de igual manera si se desea abrir un .pl doble clic sobre el .pl después Settings - User init file.. y la cerramos file - edit nombre.pl y aparecerá tu proyecto.

  2. Sintaxis de swi-Prolog:
    Bueno la sintaxis de swi-prolog es igual que cualquier otro entorno de programcion logica .
    Cualquier programa en Prolog tiene que estar escrito en un fichero de texto plano (sin formato). Lamanera mas sencilla es usar el Bloc de Notas. Dicho archivo debe poseer la extensin ”.pl” para indicar que contiene codigo fuente de Prolog.
    Un programa Prolog esta formado con un conjunto de hechos y de reglas junto con un objetivo. El archivo del codigo fuente de Prolog contendra el conjunto de hechos y de reglas y el objetivo sera lanzado desde el shell de SWI-Prolog.
    Existen ciertas consideraciones sobre la sintaxis de Prolog:
    1. Variables:
    El identificador de una variable tendra que tener su primera letra en mayusculas.
    Ej: X, Atapuerca, Cobaltina, RADgtfCdf
    2. Constantes:
    La primera letra de una constante deber´a estar escrita en min´usculas.
    Ej: a, incienso, roberto, rADgtfCdf
    Tambi´en se consideran constantes a los n´umeros,
    Ej: 1, 5.02, 0.7
    las palabras entre comillas simples
    Ej: ’a’, ’A’, ’a a’
    y la lista vacıa [ ].
    3. Funciones:
    Al igual que las constantes, su primera letra debe ser una minuscula. Debera estar seguido de un conjunto de terminos (otras funciones, variables o constantes) encerrados entre parentesis.
    Ej: f(c,X), conc arbol(Hijo Izq, Raiz, Hijo Der), rADgtfCdf(RADgtfCdf, rADgtfCdf)
    4. Predicados:
    Su sintaxis es la misma que la de las funciones aunque, por su localizacion dentro de la clausula (es decir, dentro del programa Prolog), el compilador los identificara como tal, y no como funciones.
    Ej: f(c,X), conc arbol(Hijo Izq, Raiz, Hijo Der), rADgtfCdf(RADgtfCdf, rADgtfCdf)
    Tambien existe la posibilidad de tener predicados 0-arios.
    5. Hechos:
    Son clausulas de Horn que poseen un unico predicado en la cabeza y ninguno en el cuerpo. Tienen la siguiente forma en sintaxis de logica de primer orden: P
    En Prolog no se escribe la flecha sino que se pone un punto al final: p.
    donde p es un predicado y tiene que seguir su sintaxis. Ej:
    padre(aaron, maria).
    compositor(shostakovich).
    shostakovich(compositor).
    6. Reglas:
    Son clausulas de Horn que poseen un ´unico predicado en la cabeza y uno o m´as en el cuerpo.
    Tienen la siguiente pinta:
    P← Q1,Q2,Q3 escritos en sintaxis clausular o
    P←Q1 ^ Q2 ^ Q3 escritos en sintaxis de logica de primer orden.
    En Prolog la flecha se sustituye por ”:-”, las conectivas conjuntivas se escriben como comas ”,” y la regla termina en punto:
    p :- q1, q2, q3.
    donde, al igual que los hechos, p y q1, q2 y q3 son predicados. Ej:
    cuadrado(X) :- poligono(X), numero_lados(X,4).
    7. Objetivos:
    Son clausulas de Horn que no poseen ningun predicado en su cabeza:
    &← Q1,Q2,Q3
    Los predicados se escriben separados por comas y terminados en punto. Solo pueden sen lanzados desde el shell de SWI-Prolog.
    ?- padre(X, Y),padre(Y, Z).
  3. Compilacion y ejecucion en swi-prolog:
    La codificacion en swi- prolog es la misma que todos los editores de prolog solo que aquí no declaras la variables que vas a utilizar, las funciones básicas serian:
    write, fail, nl, is ,!,:- dynamic, retract, assert, etc ;

    Algunos códigos como disktra , autómata, gramaticas, pequeño sistema experto, operaciones con listas , ordenación por mezcla selección inserción, vectores , matrices, problemas con recursion, torre de hanoi, búsquedas , etc, son los que se puedieron desarrollar en el laboratorio del curso de programacion logica dictado por Ivan sipiran.
    Para complilar un proyecto Compile-Compile buffer y para ejecutarlo en la consola de swi-prolog (figura anterior) escribir nombreReglaoHecho. y enter.



  4. Todas las soluciones a un objetivo:
    Existen predicados que no se paran cada vez que llegan a una hoja exito en el arbol de vuelta atras sino que realizan todo el arbol que esta por debajo de un objetivo dado y guardan las soluciones (unificaciones) en una lista.
    findall(+Template, +Goal, -Bag): realiza todo el arbol de backtracking del objetivo Goal. Cada vez que llega a un exito unifica las variables con la plantilla Template e introduce el resultado en la lista Bag.
    5 ?- listing.
    dios_egipcio(amon).
    dios_egipcio(anubis).
    dios_egipcio(apis).
    dios_egipcio(ra).
    Yes
    6 ?- findall(X,dios_egipcio(X), L).
    X = _G362
    L = [amon, anubis, apis, ra]
    yes
    bagof(+Template, +Goal, -Bag): identico a findall/3 excepto que si el objetivo posee variables libres entonces primero probara la unificacion con esas variables libres y despues realizara el arbol de vuelta atras para cada una de esas unificaciones, parando cada vez.
    ?- listing.
    vida(carlos_III, 1716, 1788).
    vida(carlos_IV, 1748, 1819).
    vida(fernando_VII, 1784, 1833).
    yes
    ?- bagof([A,B], vida(A, B, C),L).
    A = _G371
    B = _G374
    C = 1788
    L = [[carlos_III, 1716]] ;
    A = _G371
    B = _G374
    C = 1819
    L = [[carlos_IV, 1748]] ;
    A = _G371
    B = _G374
    C = 1833
    L = [[fernando_VII, 1784]] ;
    No
    Si no queremos que se pare cada vez que encuentre una unificacion debemos usar el sımbolo ˆ como
    en el ejemplo:
    ?- bagof([A,B], C^vida(A, B, C),L).
    A = _G383
    B = _G386
    C = _G391
    L = [[carlos_III, 1716], [carlos_IV, 1748], [fernando_VII, 1784]] ;
    No
    setof(+Template, +Goal, -Set): igual que bagof/3 pero la lista Bag es devuelta ordenada y sin duplicados.
  5. Interfaces en swi-prolog usando XPCE:
    La creacion de interfaces en swi-prolog no es tan complicada como podriamos imaginarnos por ejemplo tenemos lo siguiente :
    primerVentana:-new(D, dialog('Nombre de tu ventana')), send(D, open).

    Existen cuatro predicados basicos que te permiten interactuar con los objetos de swi-prolog :

    ?? new(?Reference, +NewTerm): Este predicado recoge dos parámetros, el primero recogería la referencia que se le asigna al nuevo objeto, ya que new se usa para crear objetos. El segundo parámetro le indicaría el objeto que se quiere crear.

    ?? send(?Receiver, +Selector(...Args...)): El primer parámetro del predicado es una referencia al objeto que deseemos enviarle un mensaje. El segundo parámetro indicará el método al que queremos invocar, lo cual indicaremos junto a los argumentos que queremos enviarle al método.

    ?? get(?Receiver, +Selector(+Argument...), -Result): Los dos primeros parámetros tienen el mismo significado que para send, sin embargo el último parámetro sirve para recoger el valor que nos devuelva el método que hallamos invocado.

    ?? free(?Reference): libera la memoria asociada al objeto que se le indica en el primer parámetro.

    Los objetos que podemos manejara en swi-prolog son:
    button
    label
    menu
    menu_bar
    menu_item
    popup
    slider
    window
    int_item
    editor
    text
    text_item
    picture
    etc.

    Cada uno de estos objetos como vimos en el ejemplo primeraVentana se alamcenan en variable por intuicion podemos concluir que para agreagar un boton a una ventana primero crearemos ambos objetos y despues agregaremos la variable de un boton a la variable de la ventana.

    Todos estos objetos tienen atributos como:
    size
    display
    margin
    colour
    style
    background
    font
    etc.

    Explicare algunos Objetos con mayor detalle:

    DIALOG
    Esta es la clase básica para crear dialogos.
    Constructor:
    dialog(label=[name], size=[size], display=[display])
    name: indica el titulo a la ventana
    size: es de tipo size y sirve para indicar el tamaño de la ventana display: indica donde queremos que se visualize (mejor no tocar este parametro si no sabemos que estamos haciendo) Podemos observar que todos los parametros son opcionales, aunque siempre es bueno ponerle un titulo a la ventana Así, como ejemplo crearemos un dialogo con titulo ‘Titulo del dialogo’ y de tamaño 440 x 320.
    new(D, dialog(‘Titulo del Dialogo’, size(440, 320)) ),
    Métodos:
    Esta clase dispone de varios métodos que pueden resultar interesantes, entre ellos tenemos:
    append(Objeto): Insertaria el objeto Objeto dentro del dialogo, visualizandolo en
    el mismo, por ejemplo sirve para insertar un boton o cualquier otra cosa, como en el siguiente ejemplo:
    send(D, append(button(‘Boton 1’)))
    open(): abre la ventana de diálogo visualizandola en pantalla:
    send(D, open),
    destroy(): cierra la ventana de diá logo visualizada en pantalla:
    send(D, destroy),

    BUTTON
    Esta es la clase básica para crear botones
    Constructor:
    button(name=name, message=[code]*, label=[name] )
    name: indica el nombre del boton (si no se especifica la etiqueta que queramos que tenga el boton, entonces adoptará una etiqueta con el mismo texto que name)
    message: indica el mensaje o acción que queremos que sea ejecutado cuando pulsemos sobre el botón con el ratón.
    label: Indica la etiqueta que queremos que se muestre en el boton.
    new(Boton, button(‘Salir’, message(Dialogo, quit)))

    LABEL
    Esta es la clase básica para crear etiquetas de texto
    Constructor:
    label(name=[name], selection=[stringimage], font=[font])
    name: indica el nombre de la etiqueta
    selection: puede ser una cadena o una imagen que queremos que sea mostrada en el lugar donde aparece la etiqueta.
    font: permite indicar la fuente en la que queremos mostrar el texto
    new(L, label(nombre, ‘texto que queramos que sea mostrado’)),

    WINDOW
    Esta clase sirve para crear ventanas donde dibujar o poner otros objetos graficos
    Constructor:
    window(label=[name], size=[size], display=[display])
    name: indica el nombre de la ventana
    size: indica el tamaño que queremos tenga la ventana
    display: indica donde queremos que aparezca (recomendamos no usar este parametro)
    Por ejemplo para crear una nueva ventana (de gráficos) de tamaño 320x200 pixels new(W, window(‘nombre ventana’, size(320, 200)),
    Métodos:
    Para esta clase nos interesarán básicamente los métodos ‘display’ y ‘flush’: display(figure, point): sirve para mostrar una figura en un lugar determinado de la ventana una determinada figura (que por ejemplo puede ser una imagen) y point que indicará las coordenadas (x,y) de la ventana donde queremos que se muestre.
    El siguiente ejemplo mostraría la figura Figure en la posicion (22, 32) de la ventana W.
    send(W, display, Figure, point(22,32))
    flush(): sirve para redibujar la venana que invoca al método, es decir, si estamos realizando una serie de llamadas y no está en el bucle principal de la ventana, entonces podemos llamar a este método para redibujar la ventana y los elementos que hayamos creado o movido.
    send(W, flush)

    Otros predicados y funciones importantes serian:
    timer: new( timer(0.2,'Aqui lo que se ejecutaro cad cierto tiempo')

    declarar variables globales: :- pce_global(@'aquinombre varglobal', new('objeto que sera global')).

    ubicacion de objetos dentro de otro objetos: right ,below ,next_row

    para cambiar forma de cursor: new(cursor('nombre del nuevo cursor')

    para retornar y esperar confirmacion de un objeto: return confirm

    para ejecutar predicados con parametros : message,?selection ejemplo-> message(@prolog, nombrepredicado, TI?selection)

    retrazar una ejecucion: sleep(10)

    etc.

    Manejo de eventos:
    Para manejar los eventos de mouse como los de teclado aqui les dejo su estructura .
    Para mouse:
    click_gesture

    Para teclado:
    key_binding

    Algunos eventos:
    handler
    handler_group
    key_binding
    click_gesture
    connect_gesture
    move_gesture
    move_outline_gesture
    resize_gesture
    resize_outline_gesture

    Manejo de imagenes :
    swi-prolog te permite manejar diferentes formatos de imagenes como por ejemplo JPEG, GIF, BMP y PNM.
    Para utilizar las imagenes primero tenemos que indicar el directorio en donde se encuentran

    :-pce_image_directory(‘direccion de la carpeta de imagenes ’)

    despues procedemos a seleccionar el nombre de la imagen:

    resource(fondo, image, image(‘nonbre de la imagen’)).

    Para poder mostrar la imagen fondo en un dialogo primero debemos primero debemos pasar la imagen a Bitmap para luego si mostrarla en el dialogo o ventana.
    Para mover imagenes tenemos los siguientes atributos:

    send(Figure, move, point(X, Y)).
    send(Figure, relative_move, point(X, Y)).

    Las imagenes se comportan igual que cualquier objeto visto anteriormente y se les puede agregar eventos de mouse como de teclado.

    Funciones para un entorno grafico:
    La principales funciones para dibujar con swiprolog serian:
    arrow
    bezier
    bitmap
    box
    circle
    ellipse
    arc
    line
    path
    text
    etc.

    Creacion de ejecutables swi-prolog:
    A continucaion un codigo para crear ejecutables :

    save(Exe):- pce_autoload_all, qsave_program(Exe,[ emulator(swi('bin/xpce-stub.exe')), stand_alone(true), goal(main) ]).

    Descargar ejecutables que desarrolle para el curso de programacion logica en swi-prolog:
    Tan solo debo hacerles recordar que los ejecutables de swi-prolog no son tan buenos como quisieramos pues su ejecucion se hase un poco pesada.
    Para ejecutar algun ejecutable primero descargar la carpeta Bin dentro de ella deberan de poner los ejecutables y posteriormente daran doble click sobre cada uno respectivamente.

    Descargar Carpeta Bin

    Descargar Tres raya swi-prolog
    Descargar Snake swi-prolog
    Descargar Sistema Experto swi-prolog
    Descargar Damas swi-prolog
    Descargar Automata-redPetri swi-prolog
    Descargar Tetris swi-prolog


  6. Archivos y Bases de datos en swi-prolog:
    Para archivos seria:
    Escritura: tell(achivo.txt'), write(primero.'), nl, write('segundo.'), nl, told.
    Lectura: see('archivo.txt'), read(P), read(S).

    Para base de datos mysql swi-prolog le dejo un pdf ojala les sea de utilidad:

    Tutorial mysql con swi-prolog

  7. Conectar Java con swi-prolog:
    Los pasos serian en si los siguientes:
    agregar alas variables de entorno del sistema operativo los siguientes direcciones talvez las direcciones no son las mismas buscar y poner la direccion indicada de cada uno si no conecta reiniciar la maquina o volver a intentar todo de nuevo.

    path=C:\Archivos de programa\Java\jdk1.5.0_09\bin;%path%
    path=C:\Archivos de programa\Java\jdk1.5.0_09\lib\tools.jar;%path%
    path=C:\Archivos de programa\Java\jdk1.5.0_09\jre\lib\rt.jar;%path% path=C:\Archivos de programa\pl\bin;%path%
    path=C:\Archivos de programa\pl\lib\jpl.jar;%path%

    Aqui les dejo un codigo de java-swiprolog que se encuentra en la ayuda de swi-prolog . Tambien lo pueden encontrar en C:\Archivos de programa \pl\doc\packages\ examples \jpl \java\Family
  8. Descagar codigo de Family

    Tambien unos ejemplos que encontre en internet para la coneccion java con swi-prolog
    ojala les sea de utilidad (son de calculadora y tictactoe).

    Descargar Ejemplos java con swi-prolog


  9. Sockets en swi-prolog:
    Para el manejo de sockets en swi-prolog ai les dejo un codigo que encontre y me sirvio , ojala les ayude a comprender un poco mas sobre este tema de sockes :

    %--------------Servidor.pl-----------------------
    server(Port):- tcp_socket(Socket), tcp_setopt(Socket, reuseaddr), tcp_bind(Socket, Port), tcp_listen(Socket, 0), tcp_open_socket(Socket, InStream, _OutStream), add_stream_to_pool(InStream,get_requests_from_clients(Socket)), stream_pool_main_loop.
    get_requests_from_clients(Socket):- trim_stacks, tcp_accept(Socket, ClientSocket, ClientIP), tcp_open_socket(ClientSocket, InStream, OutStream), add_stream_to_pool(InStream,get_request(InStream,OutStream,ClientIP)).
    get_request(InStream,OutStream,_ClientIP):- catch( read(InStream, Request), _, (writeln(error1), close(InStream), close(OutStream),delete_stream_from_pool(InStream), fail) ),
    close(InStream),
    ( Request==end_of_file -> ( writeln(error2),close(OutStream), delete_stream_from_pool(InStream),fail) ; true ),
    process(Request,Answer),
    catch( (write_canonical(OutStream, Answer), write(OutStream, '.\n')), _, (writeln(error3), close(OutStream), delete_stream_from_pool(InStream),fail) ),
    close(OutStream),
    delete_stream_from_pool(InStream).
    get_request(_InStream,_OutStream,_AgentIP).
    process(Message,test_ok(Message)).
    :-prolog_ide(thread_monitor), thread_create(server(4000),_, [alias(server),detached(true)]).


    %------ ------Clientes.pl ---------------
    create_clients:- between(1,8,N), term_to_atom(client(N),Client), thread_create(client(N), _, [alias(Client),detached(true)]), fail.create_clients.
    client(N):- Port is 4000+N, between(0,10000,F), sleep(0.0001), once( request(client(ip(127,0,0,1),Port), server(ip(127,0,0,1), 4000),hello_world(F)) ), fail.client(N):- writeln(client_finished(N)).
    request(client(_ClientIp,ClientPort), server(ServerIp,ServerPort),Message):- tcp_host_to_address(Host,ServerIp),
    repeat, tcp_socket(Socket), tcp_setopt(Socket, reuseaddr),
    catch( tcp_connect(Socket, Host:ServerPort), _, (writeln(error(ClientPort,' Client cannot tcp_connect.')),tcp_close_socket(Socket),fail) ),
    tcp_open_socket(Socket, ReadFd, WriteFd),
    catch( (write_canonical(WriteFd,Message), write(WriteFd, '.\n')), _, ( writeln(error(ClientPort,' Client cannot tcp_connect.')),tcp_close_socket(Socket),fail) ),
    close(WriteFd),
    wait_for_input([ReadFd], [ReadFd], 0),
    catch( read(ReadFd,Answer), _, ( writeln(error(ClientPort,' Client cannot tcp_connect.')), close(ReadFd),fail) ),
    close(ReadFd),
    writeln(answer(ClientPort,Answer)).
    :-create_clients.