-[ 0x09 ]-------------------------------------------------------------------- -[ SISTEMAS EXPERTOS ]------------------------------------------------------- -[ by Falken ]--------------------------------------------------------SET-17- _ _ (_) | | ___ _ ___| |_ ___ _ __ ___ __ _ ___ / __| / __| __/ _ \ '_ ` _ \ / _` / __| \__ \ \__ \ || __/ | | | | | (_| \__ \ |___/_|___/\__\___|_| |_| |_|\__,_|___/ _ | | _____ ___ __ ___ _ __| |_ ___ ___ / _ \ \/ / '_ \ / _ \ '__| __/ _ \/ __| | __/> <| |_) | __/ | | || (_) \__ \ \___/_/\_\ .__/ \___|_| \__\___/|___/ | | |_| by Falken Introduccion =-=-=-=-=-=- Hacia tiempo que no escribia algo, y ya iba siendo hora, verdad? Al grano. He comprobado como ultimamente ha crecido el interes por la inteligencia artificial, publicandose articulos en algunos fanzines de tematica under. Asi que en este numero vamos a tratar un oco por encima lo que es la inteligencia artificial, en que nos puede servir, y vamos a poner un ejemplo en C de un sistema experto. Y que conste que C no es el lenguaje mas apropiado para la inteligencia artificial. Para algo tenemos los tradicionales Lisp y Prolog. (A quien he oido decir que Java iba a sustituir al Lisp?) Breve historia... de la inteligencia =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- Hace unos a~os la inteligencia artificial paso por un momento que quizas podriamos considerar de esplendor en lo que a imagen se refiere, pero no en cuanto a resultados. Todos nos quedabamos fascinados viendo ejemplos de maquinas que aprendian, mantenian conversaciones, resolvian problemas. De hecho, en 'Juegos de guerra', mientras que para mucha gente el protagonismo lo tiene David LightMan como hacker, para otros lo tiene la WOPR como maquina inteligente, que consigue aprender algo que mucha gente ni siquiera entiende. Pero eso es una pelicula, y la realidad esta aun muy lejos de esos extremos. Aunque hay leyendas... ;) El primer problema al que nos enfrentamos cuando hablamos de inteligencia artificial es el propio hecho de la inteligencia. Que es la inteligencia? Esta claro que se puede reproducir la inteligencia, aunque algunos se empe~an en demostrar lo contrario, comportandose como idiotas toda su vida. Pero de lo que se traa es de controlar ese proceso de inteligencia. De ser capaces de definir que es lo que distingue un comportamiento inteligente de otro no inteligente. En otras palabras. Se trata de averiguar que es realmente la inteligencia. Durante a~os se estuvo de acuerdo con ciertas definiciones, como la que propuso Alan Turing. Decia que una maquina se podia considerar inteligente si superaba cierta prueba. La prueba consiste en tener a una persona en una habitacion y a la maquina en otra. Una persona fuera de ambas, y sin poder entrar a ninguna, raliza las preguntas que desee, a ambas entidades. Tanto la maquina como la persona responden lo que crean oportuno. Si no es posible determinar con total certeza cual es la persona y cual la maquina, entonces la maquina habra de considerarse inteligente. Este test, en mi opinion y en la de otros que saben mas que yo del tema, ha sido ampliamente superado. De hecho, por eso hoy dia no se le considera valido. El nacimiento de la Inteligencia Artificial (IA pa los amigos ;) ), se ha establecido en 1960, con la creacion del LISP por John McCarthy, del MIT. Justo un a~o despues, Marvin Minsky, tambien del MIT escribiria un tratado titulado 'hacia la inteligencia artificial'. Quizas el programa mas conocido que realmente nunca supero el test de Turing, aunque algunos asi lo consideren, es Eliza, de Joseph Weizenbaum, creado en 1964. Un programa capaz de mantener una conversacion, parodiando a un psicoanalista. Esa era la intencion de Weizenbaum cuando lo creo: burlarse de los psicoanalistas de su epoca. La sorpresa se la llevo el, cuando su secretaria le pidio permiso para poder usar a Eliza con otra persona que se lo habia solicitado, pues a ella le habia resuelto los problemas que tenia. Weizenbaum se esforzo en demostrar primero que Eliza no era inteligente, y segundo, que era peligroso. La verdad, en mi opinion no es inteligente,pero si util. Un buen psicoanalista no te resuelve el problema que tengas, te hace pensar para que tu seas capaz de rsolverlo por ti mismo. Y eso es lo que hacia Eliza. A menos que se refiera al peligro para el psicoanalisis, que entonces muchos se quedarian sin trabajo. El programa que causo un mayor revuelo fue el Doctor, de Borrow (espero haberlo escrito bien ;) ). Se trata de una version ampliada de Eliza, que realmente supero el test de Turing. Borrow lo estaba desarrollando como hobby, y lo dejo funcionando en el ordenador de su despacho mientras atendia otros asuntos. Su jefe se puso en contacto con el, o al menos eso creia. Conectado a la terminal, confundio al Doctor con Borrow, dandose cuenta del error cuando se le olvido finalizar una frase con el punto. Esto era una condicion necesaria para que Doctor recogiera la frase, la analizara y respondiese en consecuencia. Pero no respondio... Y al final todo se descubrio. Sigo sin creer que Dector fuera inteligente. Solo seguia un automata que en funcion de una entrada generaba una salida. Como una calculadora vulgar y corriente, pero mas entretenido. Despues llego Shrdlu. Mas loco que ninguno de los anteriores. Te cambia de tema de conversacion cuando de sale de las narices, y lo mejor es que realmente parece inteligente. Pero volvemos al mismo punto de partida. Que es la inteligencia? Generalmente, aunque tengamos la inteligencia delante de nuestras narices, no nos daremos cuenta. Ni siquiera lo hacemos con los animales. Veamos. Su estructura biologica les impide vocalizar como un humano. Pero eso no dice que no sean inteligentes. De hecho, un animal, aparte de entenderse con los propios de su especie, aprenden a entender a los humanos, aunque sean cosas reducidas, e incluso a otras especies. Y sin embargo, el ser humano solo entiende al ser humano, y a veces ni eso. Un ejemplo lo tenemos con la gorila Koko. Habla usando el lenguaje de signos de los sordomudos y mantiene perfectamente una conversacion. Hace poco incluso sele adapto una terminal (menudo tecladito para soportar sus 'delicados dedos'), y estuvo una hora y pico charlando con la gente que lo queria a traves de Internet. Asi que si ni siquiera somos capaces de discernir con certeza la inteligencia en un ser vivo, como lo vamos a hacer en una maquina? Ramas de la IA =-=-=-=-=-=-=- Con el paso del tiempo, la inteligencia artificial ha ido evolucionando. En esta evolucion han surgido diversas ramas, algunas de las cuales no tienen nada que ver con las demas. Una de las mas conocidas es la busqueda de soluciones, que ademas es la que de momento esta mas cerca de las redes. La busqueda de soluciones tiene su ejemplo mas conocido en los programas de ajedrez. Estos programas exploran un arbol evaluando la posicion de cada pieza dentro del tablero, analizando a su vez las jugadas posteriores para determinar cual es el movimiento mejor o en su caso, el menos malo. Pero nosotros tenemos un ejemplo mucho mas cercano. En la red Internet. Cuando un paquete IP no puede llegar a su destino por un camino, se busca uno alternativo. Y ahi entran en juego los algoritmos de busqueda usados en inteligencia artificial. De hecho, los algoritmos de prediccion de saltos de los modernos procesadores y los algoritmos de gestion de procesos de los sistemas multitarea siguen reglas muy proximas a los algoritmos de busqueda de la inteligencia artificial. Otro campo de interes es el del procesamiento del lenguaje natural. Aqui entran programas como Eliza, Doctor o Schrdlu. Pero mucho mejores. Desde luego, ninguna empresa hoy piensa en desarrollar un programa que mantenga una conversacion con el usuario, a no ser que se trate de un programa que intente convencernos para que compremos Windows 2000. Esta rama de la IA se aplica especialmente a correctores ortograficos que no solo miran que una palabra este en un diccionario. Pero sobre todo a los archipopulares traductores automaticos. Hay que tener presente que entre los diferentes idiomas existen diferencias de expresion que no se solucionan simplemente con cambiar una palabra de un idioma a otro. Ademas, junto con otro campo de la IA que ahora veremos, es el ideal para los sistemas de reconocimiento de voz dedicados a procesadores de texto. Os imaginais un programa que segun le dictais os corrige gramatical y sintacticamente... que rollo, no? Lo siguiente es el reconocimento de modelos... Interesante y a la vez util, sobre todo en fabricas, usado en conunto con un control de robotica. Por seguir, podemos segui tratando de la logica, la logica difusa, y las ultimas tendencias como la vida artificial. Pero de lo que va a tratar este articulo principalmente es de los sistemas expertos. De que son, como funcionan y para que se usan. Sistemas expertos =-=-=-=-=-=-=-=-= Realmente no hay mucho que decir sobre los sistemas expertos... Se trata de sistemas que son expertos. A que lo he dejado claro? ;) Bromas aparte. Un sistema experto trata de reproducir a un experto en una materia concreta. Imaginemos a una persona que no tiene mucha idea de ordenadores y se ha encontrado una tarjeta para su equipo. No sabe para que sirve, pero tiene un amigo que es un genio de las computadoras. Vamos, que nacio con un modem/fax bajo el brazo. Da la casualidad que el dia que se encuentran no lleva la tarjea encima y sale el tema. Entonces el amigo le pregunta: Es ISA o PCI Y eso que es? la conexion al ordenador... tiene pistas grandes o peque~as? peque~as tiene conectores externos? si Cuantos? 1 Reconoces el tipo? Parece de telefono, pero es mas ancho Y solo tiene 1? Si, con dos lucecitas a un lado Tio, lo tuyo es una tarjeta de red UTP. El sistema experto, cn unas reglas para las preguntas mas estrictas, tiene que reproducir al amigo. El uso de sistemas expertos nos ayuda a evitar que se nos pasen detalles por alto cuando tenemos que tomar una decision importante, por ejemplo. Ademas, la ventaja de disponer de un sistema experto se fundamenta especialmente en que al ser un programa de ordenador, o una maquina, se hacen copias y cada uno puede tener en su casa a su propio experto, sin tener que estar dependiendo de la experiencia y formacion que requiere un experto humano. Ademas, lo que aprenda el sistema experto podra ser usado en los demas sistemas expertos, y sobre todo, no se cansa nunca. Asi nos aseguramos que no falla en un momento crucial. Claro, que nada de esto se desarrolla si no tiene unas posibilidades comerciales. Lamentable, pero es asi... Al menos lo era con la era Microsoft. La IA estaba un poco muerta, cerrada a los laboratorios de investigacion. Pero a finales de los a~os 70 se creo MYCIN, el primer sistema experto comercial. MYCIN fue un exito total. Se desarrollo en la Universidad de Standford (que curioso, como el cache kernel), con la intencion de ayudar a los medicos a diagnosticar ciertas enfermedades bacterianas. En base a la comparacion de muestras, el sistema experto elabora un criterio con el que se contrasta el criterio del medico. Hoy dia ya es impensable que un moderno hospital no cuente con un sistema experto para confirmar las decisiones de los medicos. La palabra final la sigue teniendo el medico, pero ahora cuenta con una ayuda importantisima, y que nunca falla. (Fallara el al introducir los datos, pero el programa no falla. Hace lo que esta programado). En 1978 se desarrollo otro sistema experto de exito: PROSPECTOR. Este quizas impulso mas la carrera por desarrollar mejores sistemas expertos, dado que su mision era predecir la posibilidad de encontrar depositos de minerales en una region en concreto. Minerales como petroleo, gas natural, helio... El sistema experto... por dentro =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- Fundamentalmente un sistema experto se constituye de dos partes esenciales. Son la Base de conocimiento y el Motor de inferencia. La Base de conocimiento es una base de datos constituida por los objetos de la muestra y los atributos que poseen mediante una relacion especial. Por ejemplo, la tarjeta de red anterior es el objeto, y los atributos son rj45, indicadores luminosos, etc. La relacion es 'tiene' El Motor de inferencia es el que se encarga, a partir de la Base de Conocimiento y de los datos proporcionados por el usuario, de discernir a que objeto nos referimos. Para llegar a una conclusion, podemos usar uno de tres metodos: - Encadenamiento hacia adelante: Aqui el usuario suministra los datos al sistema en un principio, y el sistema elabora una hipotesis con ellos. - Encadenamiento hacia atras: En este caso, el sistema comienza preguntando al usuario por propiedades que puede tener el objeto, creando una hipotesis inicial y trabajando en demostrarla. - Reglas de produccion: Se trata de un encadenamiento hacia atras mejorado, en el que por defecto el sistema siempre hipotetiza sobre la posibilidad que de ser eliminada elimine la mayor incertidumbre posible. Codigo fuente para entrenarse un poco =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= Aqui os dejo una version muy cutre (y con errores) de un sistema experto de proposito general muy basico. <++> set_017/SE/experto.c /* experto.c by Falken para SET * * BETA 1 * * SET - Saqueadores Edicion Tecnica, 1998 * * Sistema experto basico de proposito general que ofrece multiples * soluciones y ademas muestra el razonamiento seguido. * Basado en el fuente incluido en el libro 'Utilizacion de C en inteligencia * artificial' de Herbert Schildt, y publicado por Osborne/McGrawHill * * UNIX/Linux: gcc -o experto experto.c * DOS: DJGPP * Windows: Cygnus * * EXPERTO * */ #include "stdio.h" #include "alloc.h" #define MAX 100 struct atributo { char atrib [80]; struct atributo *siguiente; } at; struct objeto { char nombre [80]; struct atributo *alista; /* Apuntar a la lista de atributos */ } ob; struct objeto_rechazado { char nombre [80]; char atrib [80]; /* Atributo que causo el rechazo */ char condicion; /* Era necesario o se descarto por una deduccion previa */ } rj; struct objeto_rechazado r_base [MAX]; struct objeto base_c [MAX]; /* Base de conocimiento */ int n_pos = -1; /* Posicion en la base de conocimiento */ int r_pos = -1; /* Posicion en la lista de rechazos */ struct atributo *si, *no; /* listas de tiene y no tiene */ struct atributo *siguientesi, *siguienteno; main () { char ch; no=si=0x00; do { libera_lista(); ch=menu(); switch(ch) { case 'i': introduce(); break; case 'p': pregunta(); break; case 's': salva(); break; case 'c': carga(); break; } } while (ch != 'x'); } libera_lista() { struct atributo *p; while (si) { p = si -> siguiente; free (si); si = p; } while (no) { p = no -> siguiente; free (no); no = p; } } /* * Ahora codificamos la funcion encargada de crear la base de conocimiento */ introduce() { int t; struct atributo *p, *anterior_p; for (;;) { t = obtiene_siguiente(); if (t == -1) { printf ("Fuera de la lista.\n"); return; } printf ("Nombre del objeto: "); gets (base_c[t].nombre); if (!*base_c[t].nombre) { n_pos--; break; } p = (struct atributo *) malloc(sizeof(at)); if (p == 0x00) { printf ("No hay memoria suficiente.\n"); return; } base_c[t].alista = p; printf ("Introduce los atributos del objeto. ENTER para salir\n"); for (;;) { printf (">> "); gets (p->atrib); if (!p->atrib[0]) break; anterior_p = p; p->siguiente = (struct atributo *) malloc(sizeof(at)); p = p->siguiente; p->siguiente = 0x00; if (p == 0x00) { printf ("No hay memoria suficiente.\n"); return; } } anterior_p->siguiente = 0x00; } } /* * Ahora codificamos la funcion encargada de realizar las preguntas al * Sistema Experto. */ pregunta () { int t; char ch; struct atributo *p; for (t=0;t<=n_pos;t++) { p = base_c[t].alista; if (intenta(p, base_c[t].nombre)) { printf ("%s concuerda con la actual descripcion\n", base_c[t].nombre); printf ("sigo (S/N): "); ch = tolower(getche()); printf ("\n"); if (ch == 'n') return; } } printf ("No se ha(n) encontrado (mas) objeto(s)\n"); } /* * Esta funcion se encarga de comprobar un objeto. */ intenta (struct atributo *p, char *ob) { char respuesta; struct atributo *a, *t; if (!sigueno(p)) return 0; if (!siguesi(p)) return 0; while (p) { if (preg (p->atrib)) { printf ("es/ha/tiene %s? ", p->atrib); respuesta = tolower(getche()); printf ("\n"); a = (struct atributo *) malloc(sizeof(at)); if (!a) { printf ("No hay memoria suficiente.\n"); return; } a->siguiente = 0x00; switch(respuesta) { case 'n': strcpy (a->atrib, p->atrib); if (!no) { no = a; siguienteno = no; } else { siguienteno->siguiente = a; siguienteno = a; } return 0; case 's': strcpy (a->atrib,p->atrib); if (!si) { si = a; siguientesi = si; } else { siguientesi->siguiente = a; siguientesi = a; } p = p->siguiente; break; case 'p': razonando (ob); break; } } else p = p->siguiente; } return 1; } /* * Busca un atributo que no tenga el objeto y que este en la lista */ sigueno (struct atributo *p) { struct atributo *a, *t; a = no; while (a) { t = p; while (t) { if (!strcmp(t->atrib,a->atrib)) return 0; t = t->siguiente; } a = a->siguiente; } return 1; } /* * Comprueba que tenga los atributos seleccionados */ siguesi (struct atributo *p) { struct atributo *a, *t; char ok; a = si; while (a) { ok = 0x00; t = p; while (t) { if (!strcmp(t->atrib,a->atrib)) ok = 0x01; t = t->siguiente; } if (!ok) return 0; a = a->siguiente; } return 1; } /* * Comprueba si el atributo se pregunto con anterioridad */ preg (char *atrib) { struct atributo *p; p = si; while (p && strcmp(atrib, p->atrib)) p = p->siguiente; if (!p) return 1; else return 0; } /* * Esta funcion muestra el motivo por el que se sigue una determinada linea * de conocimiento. */ razonando (char *ob) { struct atributo *t; int i; printf ("Intentando %s\n", ob); if (si) printf ("es/tiene/ha :\n"); t = si; while (t) { printf ("%s\n", t->atrib); t = t->siguiente; } if (no) printf ("No es/tiene/ha :\n"); t = no; while (t) { printf ("%s\n", t->atrib); t = t->siguiente; } for (i=0;i<=r_pos;i++) { printf ("%s rechazado porque ", r_base[i].nombre); if (r_base[i].condicion == 'n') printf ("%s no es un atributo.\n", r_base[i].atrib); else printf ("%s es un atributo requerido.\n", r_base[i].atrib); } } /* * Situar el objeto rechazado en la base de datos */ rechaza (char *ob, char *at, char cond) { r_pos++; strcpy(r_base[r_pos].nombre, ob); strcpy(r_base[r_pos].atrib, at); r_base[r_pos].condicion = cond; } /* * Conseguir el siguiente indice libre del array de la base de conocimiento */ obtiene_siguiente() { n_pos++; if (n_pos < MAX) return n_pos; else return -1; } /* * Aqui va la codificacion del menu de opciones */ menu() { char ch; printf ("(I)ntroduce (P)regunta (S)alva (C)arga e(X)it\n"); do { printf ("Selecciona una opcion: "); ch = tolower(getche()); } while (!esta_en (ch, "ipscx")); printf ("\n"); return ch; } /* * Salvar la base de conocimiento */ salva () { int t, x; struct atributo *p; FILE *fp; if ((fp = fopen("experto.dat", "w")) == 0) { printf ("No puedo crear el archivo\n"); return; } printf ("Salvando la base de conocimientos\n"); for (t=0;t<=n_pos;++t) { for (x=0;xatrib);x++) putc(p->atrib[x], fp); p = p->siguiente; } for (x=0;xatrib);x++) putc ('\0', fp); } putc (0, fp); fclose (fp); } /* * Cargar una base de conociminto previamente almacenada */ carga() { int t, x; struct atributo *p, *anterior_p; FILE *fp; if ((fp = fopen("experto.dat", "r")) == 0) { printf ("No puedo abrir el archivo.\n"); return; } printf ("Cargando la base de conocimientos\n"); ini_basec(); for (t=0;tatrib);x++) p->atrib[x]=getc(fp); if (!p->atrib[0]) { anterior_p->siguiente=0x00; break; } p->siguiente = (struct atributo *) malloc(sizeof(at)); if (!p->siguiente) { printf ("No hay memoria suficiente.\n"); break; } anterior_p = p; p = p->siguiente; } } fclose (fp); n_pos = t - 1; } /* * Funcion para inicializar la base de conocimiento */ ini_basec() { int t; struct atributo *p, *p2; for (t=0;t<=n_pos;t++) { p = base_c[t].alista; while (p) { p2 = p; free (p); p = p2->siguiente; } } } esta_en (char ch, char *s) { while (*s) if (ch == *s++) return 1; return 0; } <--> Por el momento lo vamos a dejar aqui. Aun queda mucho por ver, tanto de sistemas expertos como de IA. Como os decia mas arriba, este codigo fuente tiene muchos errores, y el sistema experto no funciona precisamente bien. Asi lo teneis como ejercicio para SET 18. Venga, intentad hacer que funcione lo mejor posible, a~adirle mejoras. Y a ver si es mejor que el que os de en SET 18. Have P/Hun Falken