Archive for the ‘Anotacions informàtiques’ Category

Festa del Firefox 3.5 a Barcelona!

dijous, juliol 16th, 2009

Amb motiu de la recent sortida del navegador web Firefox 3.5 s’organitzen festes arreu del món per a celebrar-ho, com ja és  habitual amb les diferents fites i aniversaris de Mozilla. La  comunitat catalanoparlant no n’és una excepció i s’està preparant una festa a Barcelona.

La festa és el dijous 16 de juliol a partir de les 7 de la tarda i  l’emplaçament escollit és l’Espai Mallorca, al carrer del Carme,  número 55.  L’acte és organitzat per la comunitat local de Mozilla i Softcatalà, i  compta amb la col·laboració de la Fundació .cat, Mozilla Europe i el  Consell de Mallorca.


Mostra un mapa més gran

(més…)

FAT32 with SD cards on GNU/Linux or GParted: FAT32 grayed out

dissabte, maig 2nd, 2009

If you are a GNU/Linux user, you may have forgotten that there is a lot of people behaving in a strange way, like using NTFS or FAT32. At least, I sometimes do. Today I got a pendrive already formatted (FAT32) and, when I plugged it in, I pretended to delete its contents. Debian told me «I can’t: it’s read only». It wasn’t read only, though. It had been  auto-mounted with standard methods. Since I wanted to delete all contents, I reckoned I could format it. Okay, it’s not one of the best practices because it’s a SD card and has a writing limit, but I just use it once a month.

debian:/home/edu# gparted

I umount /dev/sdf in order to format it, and… fat32 is grayed out. I can just use ext2, ext3, swap and reiserfs.

What nobody told me is that I need the dosfstools package:

debian:/home/edu# apt-get install dosfstools

And after that, everything worked fine. I now own a fat32 formatted 1Gb device.

Com fer servir Java, JDBC i GNU/Linux

dissabte, abril 25th, 2009

A la facultat ens han donat instruccions per a treballar amb Java i JDBC des de Windows. Com que alguns no fem servir aquest sistema inoperatiu per motius tant tècnics com ètics, m’hi he barallat una estoneta i he trobat com fer-ho amb GNU/Linux. No és complicat :)

Entorn

Java

Primer de tot ens cal l’entorn per desenvolupar aplicacions en Java

apt-get install sun-java6-jdk

Amb això no n’hi ha prou per fer un Hello World. GNU/Linux permet tenir diverses màquines virtuals instal·lades, i per defecte en ve una de lliure (cosa que ja em sembla bé). Volem desenvolupar en un entorn tan semblat a la facultat com sigui possible, així que ens toca canviar la màquina virtual i posar la privativa:

artoo:/home/edu# update-alternatives --config java

Hi ha 3 alternatives que proveeixin «java».

Selecció     Alternativa
-----------------------------------------------
1    /usr/bin/gij-4.3
+        2    /usr/lib/jvm/java-gcj/jre/bin/java
*         3    /usr/lib/jvm/java-6-sun/jre/bin/java

Premeu retorn per a mantenir l'opció per defecte[*], o introduïu un número de selecció:

Volem la 3.

Per treballar amb JDBC i PostgreSQL ens fa falta el driver adequat. A dia d’avui n’hi ha dos de disponibles, el 3 i el 4. Jo he necessitat el 4 perquè tinc màquina virtual versió >= 1.6
edu@artoo:~/facultat/bd/java$ java -version
java version "1.6.0_12"
Java(TM) SE Runtime Environment (build 1.6.0_12-b04)
Java HotSpot(TM) Client VM (build 11.2-b01, mixed mode, sharing)
edu@artoo:~/facultat/bd/java$

Ens baixarem un fitxer .jar, que ve a ser un tar.gz. El podem posar on vulguem, perquè després li direm al sistema on és. Jo he optat per fer-me un directori de treball per fer les pràctiques en /home/edu/facultat/bd/java :
edu@artoo:~/facultat/bd/java$ ls
classp             gestioSocis.java     HelloWorldApp.java
gestioSocis.class  HelloWorldApp.class
edu@artoo:~/facultat/bd/java$ ls classp/
postgresql.jar

Ara ja tenim els ingredients, i falta connectar-los. Caldrà exportar la variable d’entorn CLASSPATH. Pels veterans de C++, això ve a ser com quan compilem amb g++

g++ -c programa.cpp -I/includesdiversos

Cal dir-li on cercar fitxers que inclourem i que no venen de sèrie. Com si fos una variable d’entorn normal, fem:

export CLASSPATH=.:classp/postgresql.jar

i així li diem que busqui classes en el directori actual i en classp/postgresql.jar. Ara, per fi, ja podem fer les primeres proves amb JDBC.

Servidor i PostgreSQL

Necessitem un servidor Apache i PostgreSQL. L’opció més fàcil és fer servir LAMPP :

Instal·leu lampp en /opt/lampp Instruccions i paquet

Instal·leu el plugin per a PosgreSQL Instruccions i paquet

Els passos indicats a la web del plugin són:

  1. “tar xfz postgresql.tar.gz -C /tmp” Canvieu el nom de fitxer pel que hagueu baixat, és clar.
  2. “cd /tmp/postgresql-addon”
  3. “./INSTALL”

Per a iniciar el servidor POSGRESQL: /opt/lampp/lampp startpostgresql

Stop: /opt/lampp/lampp stoppostgresql

combinació usuari i contrasenya per defecte: User: root Password: lampp

És recomanable iniciar primer el servidor apache: /opt/lampp/lampp start i després el posgresql: /opt/lampp/lampp startpostgresql

Podeu veure una interfície web per a Posgres des del Firefox, tot anant a l’adreça: /localhost/phppgadmin

Com compilar amb Java

Farem un HelloWorld en un segon:

class HelloWorldApp {
public static void main(String[] args) {
System.out.println("Hello World!"); // Display the string.
}
}

Aquest és el codi. Cal desar-lo en HelloWorldApp.java. És important respectar el nom de fitxer, que ha de ser igual al de la classe principal.

Doncs apa:

edu@artoo:~/facultat/bd/java$ javac HelloWorldApp.java
edu@artoo:~/facultat/bd/java$ java HelloWorldApp
Hello World!
edu@artoo:~/facultat/bd/java$

Proves amb JDBC

Per l’assignatura de Bases de Dades de la FIB, quadrimestre 08-09Primavera, fem servir el següent escenari (font)

CREATE TABLE socis
(dni char(9),
nom char(30) NOT NULL,
telefon char(9),
numVISA char(12),
ciutatResidencia char(20) DEFAULT 'Barcelona',
PRIMARY KEY (dni));
 
CREATE TABLE tipus
(tipus char(15),
numMaxInscripcions integer NOT NULL,
PRIMARY KEY (tipus));
 
CREATE TABLE activitats
(tipusActivitat char(15),
dataInici integer,
descripcio char(50) UNIQUE,
dni char(9),
preu integer CHECK (preu > 10),
lloc char(20),
ciutat char(20),
PRIMARY KEY (tipusActivitat, dataInici),
FOREIGN KEY (tipusActivitat) REFERENCES tipus (tipus),
FOREIGN KEY (dni) REFERENCES socis);
 
CREATE TABLE inscripcions
(tipusActivitat char(15),
dataInici integer,
dni char(9),
formaPagament char(20),
dataPagament integer,
CHECK (dataInici < dataPagament),
PRIMARY KEY (tipusActivitat, dataInici, dni),
FOREIGN KEY (tipusActivitat, dataInici) REFERENCES activitats,
FOREIGN KEY (dni) REFERENCES socis);

Amb les dades a continuació (font):

INSERT INTO socis VALUES (10, 'Carme', 101,NULL, 'Hospitalet');
INSERT INTO socis VALUES (11, 'Nuria', 111, 111111, 'Hospitalet');
INSERT INTO socis VALUES (12, 'Josep', 121, 121121, 'Hospitalet');
INSERT INTO socis VALUES (13, 'Jordi', 131, 131131, 'Barcelona');
INSERT INTO socis VALUES (14, 'Imma', 141, 141141, 'Barcelona');
INSERT INTO socis VALUES (15, 'Roger', 151, 151151, 'Barcelona');
INSERT INTO socis VALUES (16, 'Oriol', 161, 161161, 'Barcelona');
INSERT INTO socis VALUES ('17', 'Mireia', 101,101101, 'Palleja');
INSERT INTO socis (dni, nom, telefon, numVISA) VALUES (19, 'Joan', 333, 333333);
INSERT INTO socis (dni, nom, telefon, ciutatResidencia) VALUES (20, 'Joan', 333, 'Sant Just');
 
INSERT INTO tipus VALUES ('capDAny', 200);
INSERT INTO tipus VALUES ('cine', 10);
INSERT INTO tipus VALUES ('teatre', 6);
INSERT INTO tipus VALUES ('discoteca', 30);
INSERT INTO tipus VALUES ('excursio', 30); 
INSERT INTO tipus VALUES ('sopar', 2);
INSERT INTO tipus VALUES ('opera', 6);
INSERT INTO tipus VALUES ('concert', 6);
 
INSERT INTO activitats VALUES ('cine', 124, 'One Milion Baby', 10, 17, 'Cinesa Diagonal', 'Barcelona');
INSERT INTO activitats VALUES ('cine', 224, 'Magnolias de Acero', 11, 16, 'La Farga', 'Hospitalet');
INSERT INTO activitats VALUES ('capDAny', 1224, 'Festa Roc Blanc', 12, 100, 'Plaça Major', 'Vic');
INSERT INTO activitats VALUES ('sopar', 425, 'Aniversari Josep', 12, 80, 'Can Jubany', 'Calldetenes'); 
INSERT INTO activitats VALUES ('teatre', 424, 'El Ratoli Viatger', 10, 15, 'Teatre Atlantida', 'Ripoll');
INSERT INTO activitats VALUES ('opera', 2345, 'La Flauta Magica', NULL, NULL, 'Liceu', 'Barcelona');
INSERT INTO activitats VALUES ('concert', 3234, 'La Casa de Vent i de Fusta', 10, NULL, NULL, 'Barcelona');
 
INSERT INTO inscripcions (tipusActivitat, dataInici, dni, formaPagament) VALUES ('cine', 124, 10, 'amex');
INSERT INTO inscripcions (tipusActivitat, dataInici, dni, formaPagament) VALUES ('sopar', 425, 10, 'sdfjñs');
INSERT INTO inscripcions (tipusActivitat, dataInici, dni, formaPagament) VALUES ('capDAny', 1224, 10, 'amex');
INSERT INTO inscripcions (tipusActivitat, dataInici, dni, formaPagament) VALUES ('cine', 124, 11, 'visa');
INSERT INTO inscripcions (tipusActivitat, dataInici, dni, formaPagament) VALUES ('sopar', 425, 11, 'visa');
INSERT INTO inscripcions (tipusActivitat, dataInici, dni, formaPagament) VALUES ('capDAny', 1224, 11, 'visa');
INSERT INTO inscripcions (tipusActivitat, dataInici, dni, formaPagament) VALUES ('sopar', 425, 12, 'sdfjñs');
INSERT INTO inscripcions (tipusActivitat, dataInici, dni, formaPagament) VALUES ('cine', 224, 13, 'sdfjñs');
INSERT INTO inscripcions (tipusActivitat, dataInici, dni, formaPagament) VALUES ('cine', 224, 14, 'sdfjñs');
INSERT INTO inscripcions (tipusActivitat, dataInici, dni, formaPagament) VALUES ('cine', 224, 15, 'sdfjñs');
INSERT INTO inscripcions (tipusActivitat, dataInici, dni, formaPagament) VALUES ('cine', 224, 16, 'sdfjñs');
INSERT INTO inscripcions VALUES ('teatre', 424, 10, 'VISA', 435);
INSERT INTO inscripcions VALUES ('teatre', 424, 11, 'VISA', 435);
INSERT INTO inscripcions VALUES ('teatre', 424, 12, 'VISA', 435);
INSERT INTO inscripcions VALUES ('teatre', 424, 13, 'VISA', 435);
INSERT INTO inscripcions VALUES ('teatre', 424, 14, 'VISA', 435);
INSERT INTO inscripcions VALUES ('teatre', 424, 15, 'VISA', 435);
INSERT INTO inscripcions VALUES ('teatre', 424, 16, 'VISA', 435);
INSERT INTO inscripcions (tipusActivitat, dataInici, dni) VALUES ('opera', 2345, 10);
INSERT INTO inscripcions (tipusActivitat, dataInici, dni) VALUES ('opera', 2345, 11);
INSERT INTO inscripcions (tipusActivitat, dataInici, dni) VALUES ('opera', 2345, 12);
INSERT INTO inscripcions (tipusActivitat, dataInici, dni) VALUES ('opera', 2345, 13);
INSERT INTO inscripcions (tipusActivitat, dataInici, dni) VALUES ('opera', 2345, 14);
INSERT INTO inscripcions (tipusActivitat, dataInici, dni) VALUES ('opera', 2345, 15);

La facultat ens facilita també un codi plantilla amb les línies indispensables per establir una connexió:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
import java.sql.*;
import java.util.Properties;
 
public class gestioSocis
   {
   public static void main (String args[])
     {
	try
	   {
	   // carregar el driver al controlador
	   Class.forName ("org.postgresql.Driver");
	   System.out.println ("Driver de PostgreSQL carregat correctament.");
 
 
	   // connectar a la base de dades
	   // cal modificar el username, password i el nom de la base de dades
	   // en el servidor postgresfib, SEMPRE el SSL ha de ser true
	   Properties props = new Properties();
	   props.setProperty("user","elMeuNomUsuari");
	   props.setProperty("password","elMeuPassword");
	   props.setProperty("ssl","true");
	   props.setProperty("sslfactory", "org.postgresql.ssl.NonValidatingFactory"); 
	   Connection c = DriverManager.getConnection("jdbc:postgresql://postgresfib.fib.upc.es:5432/laMevaBaseDeDades", props);
	   c.setAutoCommit(false);
	   System.out.println ("Connexio realitzada correctament.");
 
 
	   // canvi de l'esquema per defecte a un altre esquema
		 Statement s = c.createStatement();
		 s.executeUpdate("set search_path to elMeuEsquema;");
		 s.close();					
	   System.out.println ("Canvi d'esquema realitzat correctament.");
 
 
	   // consultar tots les socis que viuen a Hospitalet
	   // Dir quantes inscripcions té cada un 
	   String cR = "Hospitalet";
	   String consSocis="select dni,nom from socis "+
                         "where ciutatResidencia = '"+cR+"';";
	   System.out.println (consSocis);
	   s = c.createStatement();
	   ResultSet r = s.executeQuery (consSocis);
 
           String consInscr="select count(*) as numInscr "+
                      "from inscripcions i where i.dni = ? ;";
	   System.out.println (consInscr);
 	   PreparedStatement ps = c.prepareStatement(consInscr); 
 	   ResultSet rs = null;
	   int quantsSocis = 0;
	   String dni=" ";
	   String nom=" ";
	   while (r.next())
	   	   {
	   	   quantsSocis = quantsSocis + 1;
	   	   dni = r.getString("dni");
	   	   nom = r.getString("nom");
	   	   System.out.print ("El soci amb dni "+dni+" i nom ");
	   	   if (nom==null) { System.out.print ("null"); }
                     else { System.out.print (nom); }
		     ps.setString(1,dni);
		     rs = ps.executeQuery();
		     rs.next();
		     System.out.print("te ");
		     System.out.print (rs.getInt("numInscr"));
		     System.out.println(" inscripcions");
		     rs.close();
	   	   }
           r.close();
           System.out.println ("Nombre de socis consultats "+quantsSocis);
	   s.close();
 
	   // Inserir una activitat 
 
	   s = c.createStatement();
	   String inserirAct="insert into activitats "+
                      "values ('concert', 3250, 'El fantasma del museu', 10, 120, 'Romea', 'Barcelona')";
	   s.executeUpdate(inserirAct);
	   System.out.println ("Una activitat inserida");
           s.close();
 
	   // Rollback i desconnexió de la base de dades
	   c.rollback();
	   c.close();
	   System.out.println ("Rollback i desconnexio realitzats correctament.");
	   }
 
	catch (ClassNotFoundException ce)
	   {
	   System.out.println ("Error al carregar el driver");
	   }	
	catch (SQLException se)
	   {
	   System.out.println (se.getSQLState());
	   System.out.println (se.getMessage());	   
	   }
  }
}

El que passa és que està preparat per connectar-se des dels laboratoris de la uni, i a casa vull treballar en local. M’ho modifico:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
import java.sql.*;
import java.util.Properties;
 
public class gestioSocis
   {
   public static void main (String args[])
     {
	try
	   {
	   // carregar el driver al controlador
	   Class.forName ("org.postgresql.Driver");
	   System.out.println ("Driver de PostgreSQL carregat correctament.");
 
 
	   // connectar a la base de dades
	   // cal modificar el username, password i el nom de la base de dades
	   // en el servidor postgresfib, SEMPRE el SSL ha de ser true
	   Properties props = new Properties();
	   props.setProperty("user","root");
	   props.setProperty("password","lampp");
	   //props.setProperty("ssl","true");
	   //props.setProperty("sslfactory", "org.postgresql.ssl.NonValidatingFactory"); 
	   Connection c = DriverManager.getConnection("jdbc:postgresql://localhost/javafib", props);
	   c.setAutoCommit(false);
	   System.out.println ("Connexio realitzada correctament.");
 
 
	   // canvi de l'esquema per defecte a un altre esquema
		 Statement s = c.createStatement();
		 s.executeUpdate("set search_path to public;");
		 s.close();					
	   System.out.println ("Canvi d'esquema realitzat correctament.");
 
 
	   // consultar tots les socis que viuen a Hospitalet
	   // Dir quantes inscripcions té cada un 
	   String cR = "Hospitalet";
	   String consSocis="select dni,nom from socis "+
                         "where ciutatResidencia = '"+cR+"';";
	   System.out.println (consSocis);
	   s = c.createStatement();
	   ResultSet r = s.executeQuery (consSocis);
 
           String consInscr="select count(*) as numInscr "+
                      "from inscripcions i where i.dni = ? ;";
	   System.out.println (consInscr);
 	   PreparedStatement ps = c.prepareStatement(consInscr); 
 	   ResultSet rs = null;
	   int quantsSocis = 0;
	   String dni=" ";
	   String nom=" ";
	   while (r.next())
	   	   {
	   	   quantsSocis = quantsSocis + 1;
	   	   dni = r.getString("dni");
	   	   nom = r.getString("nom");
	   	   System.out.print ("El soci amb dni "+dni+" i nom ");
	   	   if (nom==null) { System.out.print ("null"); }
                     else { System.out.print (nom); }
		     ps.setString(1,dni);
		     rs = ps.executeQuery();
		     rs.next();
		     System.out.print("te ");
		     System.out.print (rs.getInt("numInscr"));
		     System.out.println(" inscripcions");
		     rs.close();
	   	   }
           r.close();
           System.out.println ("Nombre de socis consultats "+quantsSocis);
	   s.close();
 
	   // Inserir una activitat 
 
	   s = c.createStatement();
	   String inserirAct="insert into activitats "+
                      "values ('concert', 3250, 'El fantasma del museu', 10, 120, 'Romea', 'Barcelona')";
	   s.executeUpdate(inserirAct);
	   System.out.println ("Una activitat inserida");
           s.close();
 
	   // Rollback i desconnexió de la base de dades
	   c.rollback();
	   c.close();
	   System.out.println ("Rollback i desconnexio realitzats correctament.");
	   }
 
	catch (ClassNotFoundException ce)
	   {
	   System.out.println ("Error al carregar el driver");
	   }	
	catch (SQLException se)
	   {
	   System.out.println (se.getSQLState());
	   System.out.println (se.getMessage());	   
	   }
  }
}

i es fa la màgia

edu@artoo:~/facultat/bd/java$ java gestioSocis
Driver de PostgreSQL carregat correctament.
Connexio realitzada correctament.
Canvi d'esquema realitzat correctament.
select dni,nom from socis where ciutatResidencia = 'Hospitalet';
select count(*) as numInscr from inscripcions i where i.dni = ? ;
El soci amb dni 10 i nom Carme te 5 inscripcions
El soci amb dni 11 i nom Nuria te 5 inscripcions
El soci amb dni 12 i nom Josep te 3 inscripcions
Nombre de socis consultats 3
Una activitat inserida
Rollback i desconnexio realitzats correctament.
edu@artoo:~/facultat/bd/java$

PROLOG: introducció a la programació lògica – 2

dilluns, abril 13th, 2009

Avís: article orientat a estudiants d’Enginyeries en Informàtica de la FIBUPC. Basat en les explicacions a classe del professor Enric Rodríguez.

La programació lògica es cursa en les assignatures d’«introducció a la lògica» i a «lògica per a la informàtica». La utilitat directa per un fíber és: calcular respostes pel concurs «Cifras y letras» o trobar una manera de resoldre el problema de missioners i caníbals. També es fa servir per calcular horaris de l’ACB o els mateixos de la FIB.

Problema de concatenació

Inducció per concatenació:

concat([], L, L).
concat([X|Y1], Y2, [X|Y3]) :- concat(Y1, Y2, Y3).

Vegem que si L1, L2 són llistes i L3 és una variable, aleshores la consulta

edu@debian:~$ prolog
GNU Prolog 1.3.0
By Daniel Diaz
Copyright (C) 1999-2007 Daniel Diaz
| ?- concat(L1, L2, L3)

instancia (unifica) L3 amb la concatenació de L1 i L2.

Cas base

L1 és la llista buida []. Per la primera clàusula, tenim que L3 queda instanciada a L2, de manera que L3 s’instancia correctament.

Cas inductiu

Suposem que la llista L1 té almenys un element, és a dir, és de la forma [X | Y1]. Y1 amb longitud n+1. Aleshores, per hipòtesi d’inducció, la consulta

| ?- concat(Y1, L2, L3)

on Y3 és una variable, instancia Y3 a la concatenació de Y1 i Y2. Y1 té longitud n.
Per la segona clàusula, la consulta

| ?- concat([X|Y1], L2, L3).

instancia L3 a [X|Y3], que és la concatenació de X, Y1, Y2. Per tant, L3 queda instanciada correctament.

PROLOG: introducció a la programació lògica

dimarts, març 31st, 2009

Avís: article orientat a estudiants d’Enginyeries en Informàtica de la FIBUPC. Basat en les explicacions a classe del professor Enric Rodríguez.

La programació lògica es cursa en les assignatures d’«introducció a la lògica» i a «lògica per a la informàtica». La utilitat directa per un fíber és: calcular respostes pel concurs «Cifras y letras» o trobar una manera de resoldre el problema de missioners i caníbals. També es fa servir per calcular horaris de l’ACB o els mateixos de la FIB.

Introducció

Avui en dia fem servir les bases de dades relacionals. Tenim diverses taules amb continguts i entre ells diem quina relació tenen. Per exemple, si tenim una taula de ciutats i una altra de codis postals, en lloc de guardar quin codi postal pertany a cada ciutat, diem amb SQL «El codi 08030 i el 08080» pertanyen a Barcelona.

Seguint l’exemple dels apunts de classe, podríem tenir un model de base de dades deductiu en comptes de relacional. Nosaltres definim un concepte, i la base de dades ens dóna les respostes.

Ho aclarim:

Expressem les dades de la nostra base de dades com relacions o tuples:

pare(joan, pere)
pare(maria, pere)
germà(pere, vicent)
germà(pere, albert)
pare(x,y) = ‘y és pare de x’
germà(x,y) = ‘y és germà de x’

Imaginem-nos que volem incloure a la base de dades la relació tiet(x,y), que signifiqui ‘y és tiet de x’. Hi ha dues opcions:

  1. Afegir a la base de dades totes les relacions possibles de tiet. Per exemple:
    tiet(joan, vicent); tiet(joan, albert), …Aquest enfocament té l’inconvenient que pot arribar a tenir un nombre quadriàtic de noves relacions i també que es poden introduir inconsistències.
  2. Podem afegir una regla deductiva que permeti deduir quan hi ha relació de ‘tiet’ entre dos individus.

\forall x \forall y (tiet(x,y)) si  \exists z (pare(x,z) \wedge germa(z,y))\\* \forall x \forall y (tiet(x,y)) \leftarrow  \exists z (pare(x,z) \wedge germa(z,y))\\* \forall x \forall y (tiet(x,y)) \vee  \forall z (\neg pare(x,z) \vee \neg germa(z,y))\\* tiet(x,y) \vee  \neg pare(x,z) \vee \neg germa(z,y)
Adoneu-vos que la darrera expressió és una clàusula de Horn, que Prolog adora.

Així doncs, podem veure la nostra base de dades com un conjunt de clàusules:

\{ pare(joan, pere),\\* pare(maria, pere),\\* germa(pere, vicent)\\* germa(pere,albert),\\* tiet(x,y) \vee \neg pare(x,z) \vee \neg germa(z,y) \}

Observació: totes les clàusules de la base de dades són de Horn. A més a més, totes tenen exactament un literal positiu. D’aquest tipus de clàusules se’n diu clàusules de programa.

A la mateixa base de dades vista com un programa prolog, s’escriuria

pere(joan,pere).
pere(maria,pere).
germa(pere, vicenç).
tiet(X,Y) :- pare(X,Z), germa(Z,Y)

Atenció: fixeu-vos que hi ha un punt al final de cada línia.

Les consultes de programes lògics (bases de dades) es fan mitjançant clàusules de Horn amb tots els literals negatius. Per aquest motiu, a aquest tipus de clàusules se les anomena clàusules objectiu.

Per exemple, sigui F la conjunció de les clàusules 1,2,3,4,5 anteriors. Imaginem que estem interessats en fer la següent consulta a la base de  dades:

\mathbf{F} \models \exists u \exists v \ tiet(u,v)

Aquest problema és equivalent a veure que \mathbf{F} \wedge \neg (\exists u \exists v \ tiet(u,v)) és insatisfactible.

Vegem amb resolució que el següent conjunt de clàusules és instat:

\ 1.pare(joan, pere),\\* 2.pare(maria, pere)\\* 3.germa(pere, vicent)\\* 4.germa(pere,albert)\\* 5.tiet(x,y) \vee \neg pare(x,z) \vee \neg germa(z,y)\\* 6. \neg tiet(u,v)

Resolució:
Clàusules 5+6
\displaystyle \frac{tiet(x,y) \vee \neg pare(x,z) \vee \neg germa(z,y) \ \ \ \ \ \ \ \ \neg tiet(u,v)}{\neg pare(u,v) \vee \neg germa(z,v)}
amb \sigma = mgu(tiet(x,y), tiet(u,v)) = \{x=u, y=v \}
Generen la 7:
\neg pare(u,v) \vee \neg germa(z,v)

Resolem la 7 amb la 1
\displaystyle \frac{pare(joan, pere) \ \ \ \ \ \ \ \ \neg pare(u,v) \vee \neg germa(z,v)}{\neg germa(pere,v)}
amb \sigma = mgu(u = joan, z = pere)

Afegim la clàusula 8:
8. \neg germa(pere,v)

i resolem la 8 amb la 3
\displaystyle \frac{\neg germa(pere,v) \ \ \ \ \ \ \ \ germa(pere, vicent)}{\emptyset}

Una resposta a la consulta és u -> joan; v -> vicent.


Entra