Práctica 2 de Inteligencia Artificial Sistema experto de turismo por Barcelona %! Target: html %! Options: --toc --toc-level 6 %! Style: basic.css %! Encoding: utf-8 %%%%! Encoding: utf-8 - Daniel Clemente Laboreo, 45786256-H - Felix Marquardt, 1094094148 - Enero 2006. ------------------------- %%toc ------------------------- =Introducción= Se pide un sistema basado en el conocimiento (SBC) en lenguaje CLIPS, que recomiende actividades turísticas para varios días en Barcelona a partir de los gustos del usuario. =Análisis del problema= %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %%%%%%%%%%%% UNA DE LAS CINCO FASES %%%%%%%%%%%%%%%%%%%% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% ==Identificación== El primer paso es saber en qué consiste el problema, pensar en si es apropiado para resolverlo con un SBC, y encontrar fuentes de conocimiento que ayuden a solucionarlo. ===Mejor solución=== Al principio hicimos un error importante, que fue suponer que debíamos dar el //mejor// horario, de entre todos los posibles (y empezamos a hacer el código así), pero después de leer el enunciado más veces, vimos que en ningún sitio se pide la planificación que mejor se adapte a los gustos, sino simplemente una que concuerde con los gustos y restricciones. Eso hace el problema mucho más sencillo, ya que si tuviéramos que buscar el mejor horario, haría falta un algoritmo de ordenación de actividades según bondad, y eso -aparte de ser muy parecido a la primera práctica- funcionaría mejor en un lenguaje de programación convencional que en CLIPS. Sí que se puede hacer en CLIPS (y lo intentamos) pero sería demasiado complicado. En cambio, encontrar uno de los horarios que cumpla las restricciones dadas por el usuario es una tarea díficil para hacer con un algoritmo, pero fácil para un sistema basado en hechos y reglas. Por tanto, el problema es apropiado para ser resuelto por un SBC ===Fuentes de información=== Como el tema es bastante sencillo para casi cualquier persona, los "expertos" hemos sido nosotros mismos, ya que conocemos bastantes sitios de Barcelona y hemos sido turistas alguna vez. Además, uno de nosotros está aquí de Erasmus, y disponíamos de guías de turismo y actividades y horarios reales para añadir al sistema. % ¿decimos qué guía? %¿En la guía se dan consejos sobre cómo elegir un buen horario? Para la parte técnica, hemos consultado programas parecidos, como el sistema experto de "compra de PC". Éste es muy parecido al nuestro, ya que tiene que hacer varias preguntas para extraer información del usuario, y entonces llenar huecos del objeto solución con instancias que cumplan las condiciones que ha dicho el usuario. En cambio, el programa de "reparación de averías de coche" es demasiado sencillo comparado con el nuestro. Para la ontología, hemos consultado los ejemplos de Protégé (como el de los vinos), y hemos usado los conceptos de UML que nos enseñan en //Ingeniería del Software//. Además, como en el enunciado del problema es poco preciso, hemos preguntado más información a los "expertos" en el problema (los profesores), que nos han dado ideas como la de crear perfiles para distintos tipos de usuario, y nos han resuelto dudas. ===Descripción del problema=== Al final, nuestro problema queda en: + Preguntar datos sobre el usuario. Éstos incluyen, como mínimo: - número de días que va a estar en la ciudad - si quiere gastar mucho o poco - alguna otra característica de la estancia (si es cultural, de diversión, etc.) - edad, si va o no en grupo, ... - qué actividades quiere como obligatorias y cuáles prohíbe - qué actividades le gustan y cuáles no le gustan - qué comidas le gustan y cuáles no - horas preferidas para hacer las actividades - + Generar una planificación, para el número de días dicho, que: - para cada día, tenga tres franjas horarias (mañana, tarde y noche), y dos comidas (comida y cena) - en cada franja, que tenga entre 1 y 3 posibles actividades (para que el usuario pueda decidir) - que estén incluidas las activades obligatorias al menos una vez - que no incluya ninguna actividad prohibida - que tenga actividades que gusten al usuario siempre que sea posible - o si no hay ninguna, que al menos le gusten parcialmente - o como último caso, con actividades de cualquier tipo, aunque no le gusten - + Escribir en pantalla el horario resultante. + Por tanto, en un día puede haber de 3 a 9 (3 franjas * 3 recomendaciones) actividades recomendadas, pero el usuario siempre será libre de hacer lo que quiera; son recomendaciones. Ni siquiera sabemos si irá a alguna actividad o se las saltará todas, así que no podemos hacer suposiciones de que siga el horario al pie de la letra. También decidimos que si el turista quiere una //actividad obligatoria//, nos basta con ponerla una vez en uno de los días (no es necesario que aparezca cada día). En la ontología (hecha con Protégé) tiene que haber como mínimo la información del enunciado: actividades lúdicas (conciertos, discotecas, cine y teatro) y culturales (museos, monumentos, lugares pintorescos), y restaurantes y bares. Siempre daremos recomendaciones sobre sitios donde comer, uno para la comida (entre la mañana y la tarde) y otro para cenar (entre la tarde y la noche). Se explicará de forma más específica en el siguiente apartado. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %%%%%%%%%%%% UNA DE LAS CINCO FASES %%%%%%%%%%%%%%%%%%%% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% ==Conceptualización== Hay que descubrir qué elementos tiene el problema, y qué relación hay entre ellos. También saber cómo lo hace un experto de verdad para solucionar el problema: qué conocimientos necesita, que hipótesis maneja, qué reglas considera como //sentido común//, etc. ===Conceptos que aparecen=== Leyendo el enunciado, vemos que una actividad necesita tener: - Descripción: nombre, dirección - Precio - Hora de inicio - Duración - Edad para la que es apropiada - Si es apropiada para ir en grupo o no - Las actividades pueden ser: - De comer: bares, restaurantes - El resto: lúdicas, culturales, otras - Un turista tiene: - Presupuesto - Si va en grupo o no - Edad suya o de los del grupo - Gustos sobre actividades (tanto de las de comida como de las otras) - Los gustos de un usuario clasifican a las actividades en: - Las obligatorias - Las prohibidas - Las que le gustan - Las que no es cierto que le gusten (o no ha dado información útil) - ===Fases=== El problema consiste en tres partes: - Preguntas al usuario sobre los gustos - Elección de las instancias (actividades) más adecuadas - Mostrar la planificación final - ====Preguntas==== Para saber los gustos del usuario, pensamos en varias opciones: - preguntar gustos sobre instancias concretas: //¿te gustaría ver la Sagrada Familia?//. Habría cientos de preguntas; esta opción la descartamos y pasamos a preguntar datos sobre //clases//. - preguntar, para cada clase, si le gusta: //¿te gustan los monumentos religiosos?//. Pero también hay muchas clases, y habría muchas preguntas. - agrupar mucha información bajo una sola pregunta: //¿quieres visitar los lugares típicos de Barcelona?// - Nos decidimos por la tercera, ya que con pocas preguntas nos permite sacar mucha información, aunque seguimos preguntando por clases concretas (segundo método). Además, hacemos varias preguntas fijas: edad, si va en grupo, si le importa el precio, ... Hemos usado el sistema de las preguntas a falta de poder hacer cosas más complejas, como menús gráficos. Para el usuario sería más fácil marcar en una lista las actividades que le gustan y las que no (como una encuesta), y saltarse lo que vea poco interesante. También teníamos la idea de hacer perfiles de usuario (aventurero, cansado, culto, ...) y permitir al usuario modificar uno de ellos para acabar de configurarlo a su gusto, pero eso necesitaba menús más complejos y más interacción. =====Cantidad de información===== No todas las respuestas aportan la misma información. Por ejemplo, la pregunta "//¿Te gustan los museos de arte?//" tiene como respuesta //sí// y //no//. Cuando el usuario responde "sí", sabemos que le gustan los museos de arte, pero cuando responde "no", no sabemos casi nada. En algunas preguntas, la respuesta nos sirve para orientar las próximas preguntas: la primera que hacemos es "//¿Prefieres un viaje tranquilo?//" para saber si tenemos que consultarle sobre museos o sobre discotecas. Esta relación de hechos está basada en nuestro conocimiento, y naturalmente no cumple los gustos de todos los usuarios, pero sí de la mayoría. En esta parte es cuando el conocimiento del problema nos ayuda a simplificar la información. Si al usuario no le gusta el cine, probablemente no es necesario preguntar cada tipo de cine (famoso, alternativo, clásico, ...). Por eso, las preguntas sobre temas generales no son "//¿te gusta el cine?//", sino "//¿quieres opinar sobre cines?//". Estas preguntas corresponden a superclases en la ontología (clases que no son hojas) y sirven sólo para orientar las preguntas; para ello usamos hechos internos de la forma ``(nombre_de_la_información valor)``. =====Obligatorio y prohibido===== En las preguntas concretas (las hojas), como "//¿te gusta la comida china?//", hay dos respuestas más aparte del "sí" y el "no": están el "sí, es obligatorio" y el "no, lo prohíbo". Esto nos permite hacer lo que pide el enunciado: que se pueda forzar al sistema a que siempre/nunca salga un tipo de actividad, sin importar el precio. Por "obligatorio" hemos interpretado que el usuario quiere //como mínimo// una //instancia// de esa clase en toda la planificación (no en cada día). Una actividad obligatoria ha de ser muy buena, sin duda, pero tampoco conviene pasarse: si dice que quiere cine, no le vamos a poner cine cada día, por la mañana, tarde y noche. Puede que tampoco le sirva ir al cine una sola vez si va a estar un mes entero. Hay que encontrar un límite razonable que dependa de cuántos días va a estar, cosa que explicamos más adelante. "Prohibido" es más sencillo: ninguna instancia de la clase prohibida ha de salir en el horario. =====Esquema de las preguntas===== - __¿Quieres un viaje tranquilo?__ - **sí**, viaje tranquilo: - __¿Quieres visitar los lugares típicos de BCN?__ - **sí**, visitar lugares típicos (pero viaje tranquilo): - ¿Quieres opinar sobre museos? - **sí**: - ¿Te gusta el museo de historia? - ¿Te gusta el museo de arte? - ¿Te gusta el museo de tecnología? - ¿Te gusta el museo de personas célebres? - - ¿Quieres opinar sobre los monumentos? - **sí**: - ¿Te gusta edificios típicos? - ¿Te gusta los monumentos religiosos? - ¿Te gusta las esculturas? - - ¿Quieres opinar sobre teatro? - **sí**: - ¿Te gusta el teatro clásico? - ¿Te gusta el teatro improvisación? - ¿Te gusta el teatro alternativo? - - ¿Quieres opinar sobre cines? - **sí**: - ¿Te gusta el cine famoso? - ¿Te gusta el cine alternativo? - - ¿Te gustan los bares? (//si dice que sí, sólo añadimos los bares españoles//) - - **no**, no quiero lugares típicos (pero viaje tranquilo): - ¿Quieres opinar sobre teatro? - **sí**: - ¿Te gusta el teatro clásico? - ¿Te gusta el teatro improvisación? - ¿Te gusta el teatro alternativo? - - ¿Quieres opinar sobre cines? - **sí**: - ¿Te gusta el cine famoso? - ¿Te gusta el cine alternativo? - - ¿Te gustan los bares? - **sí**: - ¿Te gustan los bares españoles? - ¿Te gustan los bares irlandeses? - ¿Te gustan los bares para internacionales? - ¿Te gustan los bares de cocktails? - - - - **no**, viaje no tranquilo: - __¿Quieres visitar los lugares típicos de BCN?__ - **sí**, quiero lugares típicos (pero viaje no tranquilo) - ¿Quieres opinar sobre actividades organizadas y comerciales? - **sí**: - ¿Te gustan los viajes a fuera? - ¿Te gustan las visitas guiadas a la ciudad? - ¿Te gustan los parques de atracciones? - - ¿Te gustan las discotecas? - ¿Te gustan los clubs? - ¿Te gustan los bares? (//si dice que sí, sólo añadimos los españoles//) - ¿Quieres opinar sobre cine? - **sí**: - ¿Te gusta el cine famoso? - ¿Te gusta el cine alternativo? - - - **no**, no quiero lugares típicos (pero viaje no tranquilo) - ¿Quieres opinar sobre actividades organizadas y comerciales? - **sí**: - ¿Te gustan los parques de atracciones? - - ¿Te gustan las discotecas? - ¿Te gustan los clubs? - ¿Quieres opinar sobre bares? - **sí**: - ¿Te gustan los bares españoles? - ¿Te gustan los bares irlandeses? - ¿Te gustan los bares para internacionales? - ¿Te gustan los bares de cocktails? - - ¿Quieres opinar sobre cine? - **sí**: - ¿Te gusta el cine original? - ¿Te gusta el cine famoso? - ¿Te gusta el cine alternativo? - - - - ¿Te importa el precio? - **sí**: //añadir precio_máximo=20// - **no**: //añadir precio_máximo=100// - ¿Tienes alguna preferencia con la comida? - **sí**, me importa la comida: - ¿Prefieres un bar para comer? - **sí**: //añadimos comida española a los gustos// - **no**: - ¿Te gusta comida rápida? - ¿Te gusta comida turca? - ¿Te gusta comida japonesa? - ¿Te gusta comida mexicana? - ¿Te gusta comida china? - ¿Te gusta comida italiana? - ¿Te gusta comida española? - - - **no**, no me importa la comida: //añadimos que le gustan todos los tipos// - ¿Viajas sólo? - **sí**: - ¿Cuántos años tienes? - **no**: - ¿Cuántas años tiene la persona más joven? - ¿Cuántos años tiene la persona más mayor? - - ¿Cuántas franjas puede durar una actividad como máximo? - ¿Cuántos días quieres quedarte en Barcelona? - ====Poner actividades==== Ésta es la parte más importante del problema, y se explica en el apartado de //Implementación//. ====Mostrar la planificación==== La última fase es mostrar en pantalla la planificación final, en un formato que no sea muy complicado de entender. Mostramos el nombre y dirección de cada actividad de una franja, con cabeceras para decir qué día y qué franja estamos mostrando. Otra alternativa es hacer una tabla pequeña con identificadores cortos (por ejemplo, //[a010]//, //[a142]//, //[a857]//, ...), y poner la leyenda al final, para saber los datos completos de cada actividad. Sería más interesante crear como salida un fichero HTML con una tabla que tenga enlaces a las descripciones largas. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %%%%%%%%%%%% UNA DE LAS CINCO FASES %%%%%%%%%%%%%%%%%%%% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% ==Formalización== Una vez identificados los datos a tratar, tenemos que estudiar las generalizaciones, fiabilidad y completitud de la información. La propia //representación de la información// que hemos usado está en la siguiente sección, //Implementación//. También habrá que saber cómo interacciona el //motor de inferencia// del sistema de búsqueda (que será el de CLIPS), con todo nuestro conocimiento, representado mediante //hechos//, //reglas// e //instancias// de una ontología. ===Consistencia de la información=== En la ontología está especificado el tipo de cada atributo (por ejemplo, ``precio`` es un //Float//), y algunos tienen restricciones especiales: - ``franja`` es de tipo //Símbolo//, y sólo puede ser "mañana", "tarde" o "noche". - ``duración`` (entero) vale como mínimo 1 y como máximo 3. - las edades (mínima y máxima) van de 1 a 99. - Es importante saber que no usamos valores nulos en todo el programa: para evitar problemas, decidimos incluir siempre toda la información en cada actividad, aunque no sea relevante. Por eso, una actividad que empieza a cualquier hora tiene como franja de inicio a las 3 franjas, y una que es para todos los públicos acepta edades de 1 a 99. Si es gratis, tiene precio 0. Por tanto, representamos la falta de información mediante datos concretos. Aún así, hay algunas condiciones que pueden indicar un fallo en la información. Por ejemplo: - la edad mínima para una actividad es mayor que la edad máxima - una actividad empieza por la tarde pero dura 3 franjas (incorrecto, porque al día sólo le quedan 2) - Evitamos esto creando bien las instancias de la ontología, y con cuidado de no poner estos datos (aunque no tiene consecuencias graves). Protégé tiene un lenguaje para expresar restricciones de integridad, pero no con el tipo de base de datos que estamos usando (sí con OWL). También hay otras cosas que no pasarán, por ejemplo: - gustos inconsistentes por parte del usuario: prohíbe los cines pero obliga a que haya un tipo de cine concreto. O dice que le gusta algo que está prohibido. Esto lo evitamos eligiendo bien las preguntas para que los gustos no se interfieran entre ellos. - actividades sin franja de inicio, sin duración, sin precio, etc. No usamos valores nulos, y la ontología no los permite. - ===Incertidumbre=== Toda la información que tenemos en la ontología es fiable, consistente, fija (excepto un atributo que indica si una actividad está puesta o no, el resto no cambia con el tiempo), y precisa (excepto la franja de inicio y duración, que es muy general). La planificación que creamos, en cambio, tiene información menos precisa, ya que se hacen abstracciones sobre caro/barato o sobre si la edad es adecuada o no; pero seguimos teniendo datos fiables y consistentes. En ningún momento tenemos que corregir las decisiones tomadas, porque trabajamos siempre con hechos seguros. En parte, es porque el usuario no quiere información muy exacta (ver cada día hora a hora, saber el precio total exacto, ...). Lo que no sabemos, claro, es si la planificación que damos es la mejor, ya que para eso habría que explorarlas todas. ===Tipo y espacio de búsqueda=== Nuestro problema es de //síntesis// (no de //análisis//), y se adapta perfectamente a la definición de **resolución constructiva**: tenemos casi infinitas soluciones, y tenemos que construir una poco a poco. Obtenemos información sobre unas restricciones (mediante preguntas al usuario) y luego intentamos diseñar la solución, combinando elementos (actividades) de forma que cumplan las restricciones. Si hubiéramos usado perfiles de usuario (el tranquilo, el pijo, el culto, ...) para asociar a las actividades, el enfoque del problema podría cambiar: se podría hacer que, a partir de las preguntas que le hacemos al usuario, el sistema detectara aproximadamente en qué perfil o perfiles se encuentra. Entonces, la parte de las preguntas sería de //análisis//, en concreto se podría hacer con //clasificación heurística//. Pero nosotros no procesamos ni intentamos clasificar los datos del usuario, por tanto sólo hacemos //síntesis//. No se trata de //clasificación heurística// porque no tenemos un conjunto de soluciones predefinidas, ni hacemos //matching// con ningún patrón para clasificar las entradas. El mecanismo que usamos para hacer la //resolución constructiva// es el de **proponer y aplicar**, ya que: - tenemos mucho conocimiento sobre el dominio (todo el que nos ha dado el usuario; para eso hacemos las preguntas) - conocemos los componentes del problema: sabemos todos los datos de cada actividad - conocemos las restricciones: las hemos creado a partir de la información que da el usuario - tenemos el problema descompuesto en muchas fases: poner las actividades obligatorias, las perfectas, las que cumplen sólo dos condiciones, etc. - el método que usamos es el de elegir el operador correcto de un conjunto grande, en donde están ordenados mediante un sistema de preferencias basado en el "//salience//" de las reglas de CLIPS. - %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %%%%%%%%%%%% UNA DE LAS CINCO FASES %%%%%%%%%%%%%%%%%%%% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% ==Implementación== Incluye: cómo representamos los datos en la ontología y en CLIPS, y cómo hemos hecho el código para poner las actividades. Pero antes... ===Problemas con CLIPS=== CLIPS nos ha dado bastantes problemas: - no acepta Unicode en sus reglas - tampoco el habitual ISO-8859-1. No hemos podido poner acentos en, por ejemplo ``(gusta Bar_Irlandés)``, y hemos tenido que hacer cosas complicadas como ``(gusta Bar_Irland'es)`` (y entonces Protégé cambia la ``'`` por ``%27``). - en modo interactivo no usa las funciones habituales ``readline()`` de Linux, por lo que no se pueden usar los cursores si nos equivocamos al escribir. - es difícil de automatizar para hacer las pruebas: no acepta parámetros y hay que hacer trucos raros con la entrada estándar. - De estas cosas y otras ya hemos informado al autor. Con Protégé no ha habido ningún problema y nos gusta mucho. ===Representación de los datos=== - Cada actividad es una instancia; todas son descendientes de ``Actividad``. La jerarquía se explicará en el apartado de la ontología. - Cada día de la planificación es una instancia de ``Horario``. - A continuación se explican los atributos que usamos en estas clases. ====Nombre y dirección==== Datos sobre cada actividad; son los que se muestran en pantalla en el horario final. ====Precio==== Hemos estudiado varias formas de guardar el precio de cada actividad; por ejemplo, tener sólo un booleano que diga si la actividad es cara o no (ya que el precio exacto puede depender de muchas cosas, y cambia mucho). De esta forma, al usuario sólo habría que preguntarle que si quiere un viaje barato o caro, no que cuántos euros tiene para gastarse. Otra alternativa es preguntar el presupuesto máximo para las vacaciones, y construir un horario tal que la suma de precios de todas las actividades no lo sobrepase. Pero esto es muy inexacto, ya que el usuario no va a hacer las 3 actividades posibles que hay en cada franja, sino sólo 1 o ninguna. Por tanto, no podemos saber exactamente el dinero total que va a costarle una planificación, y eso nos hizo alejarnos un poco de los números exactos y pensar sólo en caro/barato. Al final pudimos encontrar una solución mixta, que usa precios en euros pero también clasifica en caro/barato para comunicarse con el usuario: - En cada actividad está grabado el coste medio en euros. Por ejemplo, para un cine concreto puede ser 6 euros. Cada instancia tiene su precio. - Pero al usuario sólo se le pregunta //¿te importa el precio?// y responde //sí// o //no//, sin dar números. A partir de ahí: - Si dice que //sí// le importa, ponemos un //precio máximo por actividad// de 20 euros. - Si dice que //no//, pones el precio máximo muy alto, a 100 euros - - Después, al poner actividades, sólo se usarán las que tienen un precio menor al //precio máximo por actividad// (y no es necesario consultar si el usuario dijo barato o caro). Esto tiene desventajas, ya que un cine de 18 euros cuenta como //barato// aunque para nosotros es caro, y gastarse 25 euros en un centro comercial contará como //caro//, aunque no es tan extraño. Pero éstos son ejemplos extremos; la mayoría de actividades sí que quedan en la categoría que les toca. Además, se graba el precio //medio// de cada actividad, que da más información sobre si una actividad es barata o cara. Para los usuarios expertos, se puede incluir una pregunta más avanzada: //¿cuál es el máximo precio medio que estás dispuesto a pagar por una actividad?//. Pero ya que eso son datos internos de nuestro sistema, lo ponemos nosotros a 20 ó 100 para que concuerde con los precios que tenemos en la ontología. Hay que notar también que las actividades baratas también pueden salir en la planificación de un usuario al que no le importa el precio. ====Edad permitida==== Teníamos dos posibilidades: edad //recomendada// para cada actividad, o //edad permitida// en una actividad. Hemos preguntado e investigado, y la mayoría de actividades en Barcelona no tienen una recomendación de edad concreta. Incluso es difícil clasificarlas entre niños/adultos: en un cine depende de la película, la comida es para todos, un parque de atracciones es para todo tipo de edades, los museos pueden interesar a jóvenes, etc. Quizás la única excepción son las discotecas y actividades de noche, donde haya alguna ley que prohíba la entrada a menores. Por eso hemos interpretado las edades como //edades permitidas//, o sea, que si el usuario no está en este rango de edad no se las daremos (es como si las hubiese prohibido). O sea, que en una discoteca, la edad mínima será 18, y damos la posibilidad de poner una edad máxima (quizá no hay leyes sobre esto, pero algunos sitios pueden querer prohibir la entrada a los mayores). Cada actividad tiene grabada una edad mínima y una edad máxima. Del grupo en el que va el usuario también guardamos la edad del más pequeño y del más mayor. Estas dos edades serán la misma si el usuario va sólo, cosa que también se pregunta al empezar. ====En grupo==== Igual que con la edad, no hemos encontrado actividades exclusivas para un tamaño de grupo concreto. A una actividad de grupo se puede ir solo, aunque quizás la condición inversa no es cierta: puede haber actividades necesariamente individuales, a las que no se puede ir en grupo (por ejemplo, ir a un bar pequeño donde no organizan comidas en grupo). Aún así, usamos esta información al elegir actividades, aunque como condición secundaria (es más importante el precio y los gustos que esto). Al usuario le preguntamos sólo si va en grupo o no, pero no el tamaño. Lo que contesta también sirve para preguntarle sólo su edad o las dos (del más jóven y del más viejo). ====Hora de inicio y duración==== Como con el precio, hemos pensado en grabar la hora de inicio exacta a la que empieza cada actividad, y el número de horas que dura. También pensamos en comprobar que el horario que dábamos no tenía actividades que se solaparan, pero vimos que sería repetir la primera práctica, y que no sabríamos hacerlo en CLIPS. Además, no sabemos qué camino de los que le ofrecemos seguirá el usuario, ni podemos ser tan precisos como para calcularlos. La documentación dice que el día tiene tres franjas: //mañana// (de 8 a 13), //tarde// (de 13 a 20), y //noche// (de 21 a 3). Por eso hemos visto mejor guardar sólo, para cada actividad, la franja en la que empieza; pero no la hora exacta, ya que quizás no se sabe o es irrelevante. De la misma manera, no tiene sentido guardar una duración en horas si no pretendemos ser precisos ni usar este dato para hacer otros cálculos. Sólo guardamos, para cada actividad, el número de franjas que dura, que puede ser 1, 2 ó 3. En la ontología no tendremos instancias incorrectas; por ejemplo, una actividad que empiece por la noche y dure 3 franjas. La información sobre duración no la usamos al crear la planificación, y dejamos como responsabilidad del usuario saber que, si por la mañana elige hacer una actividad que dura dos franjas, entonces no podrá ir a ninguna de las que se hacen por la tarde (a no ser que la interrumpa a medias, pero eso son cosas que no controlamos). Lo que no haremos será dejar de dar actividades para hacer por la tarde. Se permite el caso de que una actividad pueda empezar en varias franjas (el atributo será multivaluado). Y si para una actividad no importa la franja de inicio (o no es relevante), diremos que puede empezar tanto por la mañana como por la tarde como por la noche. ====Gustos del usuario==== Al hacer las preguntas del tipo "//¿te gusta nombre_de_la_actividad?//", el usuario puede decir que sí, no, obligatorio, o prohibido. Si dice que no, no aporta nada de información, pero en otro caso añadimos hechos (con ``assert``): - Si le gusta, añadimos ``(gusta nombre_de_clase)`` - Si la quiere obligatoriamente, ``(obligatorio nombre_de_clase)`` - Si la prohíbe, ``(prohibido nombre_de_clase)`` - Es importante lo de que usamos el nombre de la clase real como parámetro, por ejemplo, ``(gusta Cine_Famoso)`` porque ``Cine_Famoso`` es una clase de la ontología (subclase de ``Cine``). Antes usábamos ``(gusta cine famoso)``, que nos aportaba información a nosotros, pero no permitía automatizar las reglas que eligen actividades. De la forma en que lo hemos dejado, comprobar si la actividad ``?a`` te gusta es muy fácil, sólo hay que mirar si existe ``(gusta ?a)``. Para no poner por error como una actividad los bares y restaurantes, los gustos de comida los tenemos separados: en vez de ``(gusta Comida_China)`` ponemos ``(gusta comida Comida_China)``. Eso ayuda en las reglas de poner actividades, porque podemos escribir algo como ``(gusta ?)`` y encontrará sólo actividades lúdico-comerciales-culturales, pero no las comidas. ====Día del horario==== Un día de la planificación (que es una instancia de la clase ``Horario``) tiene los atributos ``comida_primera`` y ``comida_segunda``, y uno para cada una de las 3 franjas: ``manana``, ``tarde``, ``noche``; cada uno multivaluado (1 a 3) para poder poner las 3 alternativas. ===Poner actividades en el horario=== Ésta es la parte más importante, y la más difícil. Consiste en saber cómo piensa un turista de los de verdad cuando elige actividades. Naturalmente, las decisiones que toma no son universales, y dependen mucho del usuario. Hemos tenido en cuenta muchas posibilidades; aquí mostramos algunas, y entre ellas la que hemos usado al final. ====Condiciones que se comprueban==== Lo primero es saber el algoritmo exacto que usa el turista. Ya sabemos en lo que se fija (en las características de la actividad), pero falta decidir el orden e importancia de cada concepto. La primera lista de condiciones (ordenada) para decir si una actividad es buena fue: + La actividad te gusta. + La actividad es apta para tu bolsillo. + La actividad tiene una duración que te parece bien. + La actividad empieza en la franja que quieres o más tarde. + La actividad es apropiada para tu tamaño de grupo. + A esto hay que añadir los "axiomas": - Si es obligatoria, no hay nada que decidir; es buena. - Si está prohibida, es mala. - Si no está permitida debido a tu edad, es mala; no se puede coger. (Es edad permitida, no recomendada). - Si ya has hecho una actividad varias veces, mejor no la hagas más si quieres un horario variado. - %%%%%% Sí que podríamos haber usado la franja de inicio... %Y en realidad, la franja de inicio de una actividad no es muy importante para nosotros, %ya que el enunciado nos obliga a poner actividades por la mañana y la tarde %incluso si el usuario prefiere empezar por la tarde o noche. ====Ordenar la lista de actividades==== La primera solución en la que pensamos (**NO DEFINITIVA**) fue crear una función de comparación que se basara en esas condiciones para decidir si la actividad ``?a`` es mejor que la ``?b`` (actividades cualquiera). Entonces, podríamos hacer un algoritmo de ordenación según esta función de comparación, para que la lista de //todas// las instancias de nuestro sistema estuviera ordenada según bondad: las mejores primero, las peores al final. La lista acabaría ordenada así (de mejor a peor): + Las actividades obligatorias (que son las mejores de todas) + ``12345`` : Las actividades //perfectas//: las que cumplen todas las condiciones + ``1234.`` : Las que cumplen las 4 primeras condiciones + ``123..`` : Las que cumplen las 3 primeras + ``12...`` : Las que cumplen las 2 primeras + ``1....`` : Las que cumplen la primera + ``.2345`` : Las que no cumplen la primera, pero sí las otras + ``.234.`` + ``.23..`` + ``.2...`` + ``..345`` + ``..34.`` + ``..3..`` + ``...45`` + ``...4.`` + ``....5`` + ``.....`` : Las que no cumplen ninguna condición + Las que son para una edad no permitida + Las prohibidas + (Eso incluye toda una tabla de la verdad desordenada; media, en realidad, ya que para 5 variables salen 16 filas.) Entonces, para poner actividades en el horario, sólo tendríamos que ir cogiendo el primer elemento de la lista y ponerlo en algún hueco del horario, y así hasta que se acabe la lista o los huecos libres. Pero vimos que esto era demasiado parecido a un algoritmo típico de lenguajes secuenciales y programación orientada a objetos (lo haríamos mucho mejor con el JAVA), y también que no era necesario dar //el mejor horario//, que es lo que nos proponíamos. Así que al final no hicimos esto y usamos más reglas, hechos, y programación lógica. De todas formas, intentamos implementarlo de dos maneras: - Una función (``deffunction``) para comparar ``?a`` y ``?b``, actividades. Aquí nos encontramos con el problema de que desde una función no podíamos consultar hechos, como por ejemplo, ``(gusta Comida_China)``. - Con reglas (``defrule``) que, para toda actividad ``?a`` y ``?b``, añadieran un hecho ``(mejor ?a que ?b)`` o al revés. Eso crearía muchísimos hechos (ya que comprobaría cada actvidad con todas las demás), pero el trabajo de comparar todas con todas también iba a estar en un algoritmo de ordenación. - ====Perfectas, otras==== La primera idea que tuvimos para poner buenas actividades fue dividirlas en dos grupos: - Las //perfectas//: las que cumplen las 5 condiciones - El resto - Naturalmente, las prohibidas no se pueden poner nunca. En el horario pondríamos las perfectas, y luego el resto. Este método no es bueno, porque dentro de "el resto", hay algunas mejores que otras. ====Simplificar las condiciones ==== Pensamos en hacer las más de 16 reglas para añadir actividades comprobando las 5 condiciones (con su tabla de la verdad), más las obligatorias, y las comidas. Pero como iban a ser muchas reglas y en realidad no era necesario el mejor horario, al final agrupamos las condiciones para tener menos de 5. Nos quedamos con dos grupos: condiciones primarias (1 y 2), y secundarias (la condición 3): + La actividad te gusta + La actividad es apta para tu bolsillo + La actividad dura lo que tú quieres, empieza a la hora que quieres, y es para tu tamaño de grupo + Estas tres condiciones necesitan 8 reglas. ``` 123 --- ccc cc. c.. .cc .c. ..c ... ``` Pero aún nos queda un problema: ¿qué quiere decir, por ejemplo, //poner las perfectas//? Formalizado es: //para toda clase que cumpla las 3 condiciones, poner en el horario todas sus instancias//. Esto está bien (ponemos muchas actividades muy buenas), pero puede que no sea aceptable para el usuario: si para el usuario la actividad //Cine original// es perfecta, no podemos ponerle en su planificación una visita a //todos// los cines de Barcelona, porque entonces ya no será tan perfecta. Le gustará más que haya variedad de actividades, aunque no todas sean perfectas (en esta decisión interviene el conocimiento que tenemos sobre el problema). ====Decidir la cantidad==== Pensamos en limitar la cantidad de actividades de cada clase: por ejemplo, no poner nunca más de 2 instancias de una clase perfecta, porque entonces dejaría de ser buena. Pero claro, si las vacaciones son de sólo 1 día, repetir dos veces el mismo tipo de actividad puede no ser bueno. En cambio, si las vacaciones son de 30 días, 1 sola actividad perfecta es muy poco (sobre todo teniendo en cuenta lo buenas que son). Por eso necesitamos un límite variable, que dependa del número de días: el límite será ``N``. El proceso entonces es: + Poner N instancias de cada clase obligatoria + Poner N de todas las actividades perfectas (``123``) + Poner N de las que cumplen ``12.`` + Poner N de las que cumplen ``1..`` + Poner N de las que cumplen ``.23`` + Poner N de las que cumplen ``.2.`` + Poner N de las que cumplen ``..3`` + Poner el resto de actividades (``...``) + Pero no se puede poner una actividad si: está prohibida por el usuario, si es para una edad no apropiada, o si ya está puesta en el horario. ``N`` (entero) tiene que ser un porcentaje del número de días. Pusimos el 30% porque ya funciona bien, pero hay que sumarle 1 porque un viaje de un día no tiene tiene que tener 0 de cada tipo (0.3*1), sino 1. ``` N = número_de_días * 0.3 + 1 ``` Para un viaje de 1 a 3 días, se pone 1 de cada tipo. De 4 a 6 días, 2 de cada tipo. De 7 a 9, 3 de cada tipo. Etc. Es importante lo que quiere decir el punto (``.``) en la notación usada arriba: las condiciones son **no exclusivas**, y el punto quiere decir que una condición //no se comprueba// (no que una condición ha de ser falsa). Cuando se ponen las que cumplen ``123``, no se ponen todas (sólo ``N`` de cada clase), así que cuando toca poner las de ``12.``, aún hay posibilidad de coger alguna de tipo ``123``, ya que están incluidas en el conjunto ``12.``. Pero la posibilidad de coger una de ``123`` se va haciendo cada vez más pequeña a medida que aumenta el conjunto de actividades posibles. Así conseguimos que no sean //exactamente// ``N`` de cada tipo, sino que puede haber pequeñas variaciones. De todas formas, el último paso (``...``) consiste en poner las que //no cumplen ninguna condición en especial//, o sea, todas. Ahí están incluidas tanto las perfectas, como las obligatorias, como buenas y malas. Es una buena forma de acabar de rellenar el horario. Ésta es la solución que usamos. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %%%%%%%%%%%% UNA DE LAS CINCO FASES %%%%%%%%%%%%%%%%%%%% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% ==Prueba== Como pruebas hemos usado varios ejemplos (que están listados en la última sección): - varios casos representativos del usuario normal y típico: se está una cerca de una semana, quiere ver Barcelona y quiere probar la comida típica. El resultado es bueno, sobre todo si el número de días no es demasiado alto. - un usuario al que no le gusta casi nada (pero no lo prohíbe), ni da mucha información: la planificación final tiene actividades de todo tipo, pero sobre todo malas, porque no son las que le gustan al usuario. - un usuario al que le gusta todo: da un horario como al anterior, pero en este caso cualquier horario vale, porque todas las actividades le gustan. - un usuario que quiere estar 0 días: no se le deja escribir este número. - En general, el resultado es mejor cuantas más instancias hay en la ontología. Otra cosa que hemos comprobado es que cada actividad se ponga en la franja permitida. =Ontología= ==Decisiones== - Hay ``Actividad_comida`` y ``Actividad_no_comida``, pero todas son subclases de ``Actividad`` - Una ``Actividad_comida`` es en un restaurante, y tiene como subclases los distintos tipos de comida: rápida, japonesa, mexicana, china, española, ... - También hay bares, pero los hemos clasificado como actividades lúdicas, ya que es un sitio donde no sólo se va a comer, sino a pasar el tiempo con los amigos. Hay varios tipos de bares: irlandés, cocktails, para internacionales, y el español, donde además sirven ``Comida_Española`` (como en los restaurantes). - Las actividades de no comer se dividen en tres: ``Cultural``, ``Lúdica`` y ``Comercial``. - En ellas se clasifican los cines, museos, teatros, viajes a fuera y por la ciudad, parques de atracciones, clubs, discotecas, bares y monumentos. - ==Listado de clases== % ¿cómo? También adjuntamos una captura de pantalla. ``` CLIPS> (browse-classes) OBJECT PRIMITIVE NUMBER INTEGER FLOAT LEXEME SYMBOL STRING MULTIFIELD ADDRESS EXTERNAL-ADDRESS FACT-ADDRESS INSTANCE-ADDRESS * INSTANCE INSTANCE-ADDRESS * INSTANCE-NAME USER INITIAL-OBJECT %3ACLIPS_TOP_LEVEL_SLOT_CLASS Actividad Actividad_no_comida L'udica Bar Bar_Irland'es Bar_para_Internacionales Bar_de_Cocktails Bar_Espanol * Club Discoteca Cultural Teatro Teatro_Cl'asico Improvisaci'on Teatro_Alternativo Museo Historia Arte Personas_C'elebres Tecnolog'ia Monumento Monumento_Religioso Edificio Escultura Cine Cine_Programa Cine_Alternativo Cine_Famoso Cine_Original Comercial Gu'ia_de_la_Ciudad Parque_de_Atracc'ion Viajes_a_fuera Actividad_Comida Comida_Espanola Bar_Espanol * Comida_China Comida_Mexicana Comida_Italiana Comida_Turca Comida_Japonesa Comida_R'apida Persona Horario CLIPS> ``` ==Clase Actividad== Como ya hemos dicho, en sus atributos no se aceptan los valores nulos. ``franja`` es una combinación de ``mañana``, ``tarde`` y ``noche``. Puede ser uno de ellos, dos o tres. ``grupo`` acepta ``sí`` y ``no`` (más cómodo para el usuario, en vez de //True// y //False//). Indica si //se puede// hacer en grupo (lo normal es que sí). ``hecho`` (``sí``/``no``) lo cambiamos a ``no`` nosotros durante el programa, pero el //ingeniero del conocimiento// lo puede usar para desactivar actividades. ``` CLIPS> (describe-class Actividad) ================================================================================ ******************************************************************************** Concrete: direct instances of this class can be created. Reactive: direct instances of this class can match defrule patterns. Direct Superclasses: USER Inheritance Precedence: Actividad USER OBJECT Direct Subclasses: Actividad_no_comida Actividad_Comida -------------------------------------------------------------------------------- SLOTS : FLD DEF PRP ACC STO MCH SRC VIS CRT OVRD-MSG SOURCE(S) franja : MLT STC INH RW LCL RCT EXC PRV RW put-franja Actividad direcci'on : SGL STC INH RW LCL RCT EXC PRV RW put-direcci' Actividad edad_m'axima : SGL STC INH RW LCL RCT EXC PRV RW put-edad_m'a Actividad duraci'on : SGL STC INH RW LCL RCT EXC PRV RW put-duraci'o Actividad precio : SGL STC INH RW LCL RCT EXC PRV RW put-precio Actividad edad_m'inima : SGL STC INH RW LCL RCT EXC PRV RW put-edad_m'i Actividad nombre : SGL STC INH RW LCL RCT EXC PRV RW put-nombre Actividad grupo : SGL STC INH RW LCL RCT EXC PRV RW put-grupo Actividad hecho : SGL STC INH RW LCL RCT EXC PRV RW put-hecho Actividad Constraint information for slots: SLOTS : SYM STR INN INA EXA FTA INT FLT franja : # CRD:[1..3] direcci'on : + edad_m'axima : + RNG:[1..99] duraci'on : + RNG:[1..3] precio : + RNG:[-oo..+oo] edad_m'inima : + RNG:[1..99] nombre : + grupo : # hecho : # -------------------------------------------------------------------------------- Recognized message-handlers: init primary in class USER delete primary in class USER create primary in class USER print primary in class USER direct-modify primary in class USER message-modify primary in class USER direct-duplicate primary in class USER message-duplicate primary in class USER get-franja primary in class Actividad put-franja primary in class Actividad get-direcci'on primary in class Actividad put-direcci'on primary in class Actividad get-edad_m'axima primary in class Actividad put-edad_m'axima primary in class Actividad get-duraci'on primary in class Actividad put-duraci'on primary in class Actividad get-precio primary in class Actividad put-precio primary in class Actividad get-edad_m'inima primary in class Actividad put-edad_m'inima primary in class Actividad get-nombre primary in class Actividad put-nombre primary in class Actividad get-grupo primary in class Actividad put-grupo primary in class Actividad get-hecho primary in class Actividad put-hecho primary in class Actividad ******************************************************************************** ================================================================================ CLIPS> ``` ==Clase Horario== ``` CLIPS> (describe-class Horario) ================================================================================ ******************************************************************************** Concrete: direct instances of this class can be created. Reactive: direct instances of this class can match defrule patterns. Direct Superclasses: USER Inheritance Precedence: Horario USER OBJECT Direct Subclasses: -------------------------------------------------------------------------------- SLOTS : FLD DEF PRP ACC STO MCH SRC VIS CRT OVRD-MSG SOURCE(S) noche : MLT STC INH RW LCL RCT EXC PRV RW put-noche Horario comida_primera : SGL STC INH RW LCL RCT EXC PRV RW put-comida_p Horario tarde : MLT STC INH RW LCL RCT EXC PRV RW put-tarde Horario manana : MLT STC INH RW LCL RCT EXC PRV RW put-manana Horario comida_segunda : SGL STC INH RW LCL RCT EXC PRV RW put-comida_s Horario Constraint information for slots: SLOTS : SYM STR INN INA EXA FTA INT FLT noche : + + CRD:[1..3] comida_primera : + + tarde : + + CRD:[1..3] manana : + + CRD:[1..3] comida_segunda : + + -------------------------------------------------------------------------------- Recognized message-handlers: init primary in class USER delete primary in class USER create primary in class USER print primary in class USER direct-modify primary in class USER message-modify primary in class USER direct-duplicate primary in class USER message-duplicate primary in class USER get-noche primary in class Horario put-noche primary in class Horario get-comida_primera primary in class Horario put-comida_primera primary in class Horario get-tarde primary in class Horario put-tarde primary in class Horario get-manana primary in class Horario put-manana primary in class Horario get-comida_segunda primary in class Horario put-comida_segunda primary in class Horario imprime primary in class Horario ******************************************************************************** ================================================================================ CLIPS> ``` ==Otras ideas== Pensamos en añadir más atributos a cada actividad: - Idioma(s), importante para el turista - Si se puede fumar o no, que ahora está de moda - Descripción larga, que diga en qué consiste, precios, horarios, página web, ... - Un atributo ``es_caro`` (booleano), que permita marcar a cada una de forma subjetiva. Ahora tenemos el precio (que es objetivo), pero no es lo mismo 30 euros para un cine que para un parque de atracciones. - ==Instancias== Hemos creado más de 150, de muchos tipos y atributos, para asegurarnos de que funciona. Fragmento del ``Actividades.pins``: ``` ([Actividades_Instance_10042] of Parque_de_Atracc'ion (direcci'on "Serra de Collserola") (duraci'on 1) (edad_m'axima 99) (edad_m'inima 1) (franja tarde) (grupo s'i) (hecho no) (nombre "Parc del Laberint d'Horta") (precio 4.0)) ([Actividades_Instance_10043] of Tecnolog'ia (direcci'on "Carrer Roviralta 55") (duraci'on 1) (edad_m'axima 99) (edad_m'inima 4) (franja tarde) (grupo s'i) (hecho no) (nombre "Museu de la Ci'encia") (precio 8.0)) ([Actividades_Instance_10044] of Tecnolog'ia (direcci'on "Montjuic") (duraci'on 1) (edad_m'axima 99) (edad_m'inima 1) (franja tarde) (grupo s'i) (hecho no) (nombre "Museu Militar") (precio 7.0)) ([Actividades_Instance_10045] of Historia (direcci'on "Carrer Aristides Maillol") (duraci'on 1) (edad_m'axima 99) (edad_m'inima 1) (franja tarde) (grupo s'i) (hecho no) (nombre "Museo del Futbol Club Barcelona") (precio 10.0)) ([Actividades_Instance_10046] of Arte (duraci'on 1) (edad_m'axima 99) (edad_m'inima 1) (franja manana) (grupo s'i) (hecho no) (nombre "Museu de la Xocolata") (precio 5.0)) ([Actividades_Instance_10047] of Personas_C'elebres (duraci'on 1) (edad_m'axima 99) (edad_m'inima 1) (franja tarde) (grupo s'i) (hecho no) (nombre "Museo de Cera") (precio 5.0)) ``` =Código fuente del sistema= %!include: ``../preguntas.clp`` =Pruebas= ``` Viaje tranquilo: sí Lugares típicos: sí Museo: sí Museo de historia: obligatorio Museo de arte: sí Museo de Tecnología: prohibido Museo de personas célebres: no Monumentos: sí Edifícios: obligatorio Monumentos religiosos: no Esculturas: no Teatro: sí Teatro clásico: no Teatro de improvisación: no Teatro alternativo: sí Cine: sí Cine original: Cine famoso: sí Cine alternativo: sí Bares: sí español: irlandeses: para extranjeros: de cocktails: Comida: sí Bares para comer: sí Precio: no sólo: sí Edad mínima: 23 Edad máxima: 23 Duración: 2 Días: 4 Día 1: Manana: Museu Frederic Mar'es ; Museu Etnol'ogic ; Casa-Museu Gaud'i ; Tarde : Museu Nacional d'Art de Catalunya ; Fundaci'o Joan Mir'o ; Cine Verdi ; Noche : Ginger ; Forty ; Blank ; Comida primera: Reno Comida segunda: Bestial Día 2: Manana: The Quiet Man ; Ryan's ; Casa Mil'a ; Tarde : 'Acido 'Oxido ; Almirall ; Aribau ; Noche : Bosque ; Teatre Grec ; Bodas ; Comida primera: Bun Sichi Comida segunda: Hard Rock Caf'e Día 3: Manana: Museu Barbier-Mueller d'Art Precolombi ; Museo de Historia de la Ciudad ; Montserrat ; Tarde : Museo del Futbol Club Barcelona ; AMC Cines Diagonal Mar ; Museu Maritim ; Noche : Teatre T'ivoli ; Mercat de les Flors ; Dry Martini ; Comida primera: Mas Lluhi Comida segunda: Adelita Spring Día 4: Manana: Museu de la Xocolata ; Museu d'Art Contemporani ; Museu Egipci ; Tarde : Casa Batll'o ; La Vinya del Senyor ; Xampanyet ; Noche : Cines Icaria Yelmo Cineplex ; Imax Port Vell ; East 47 ; Comida primera: Neichel Comida segunda: Al Passatore ######################################################################### ######################################################################### Viaje tranquilo: no Lugares típicos: no Museo: no Museo de historia: Museo de arte: Museo de Tecnología: Museo de personas célebres: Monumentos: no Edifícios: Monumentos religiosos: Esculturas: Teatro: no Teatro clásico: Teatro de improvisación: Teatro alternativo: Cine: no Cine original: Cine famoso: Cine alternativo: Bares: no español: irlandeses: para extranjeros: de cocktails: Comida: no Bares para comer: Precio: no sólo: no Edad mínima: 6 Edad máxima: 50 Duración: 2 Días: 3 Día 1: Manana: Museu Etnol'ogic ; Museu Egipci ; Museu Barbier-Mueller d'Art Precolombi ; Tarde : Antic Teatre ; Ambar ; Almirall ; Noche : 'Acido 'Oxido ; Plaza Reial ; Teatre T'ivoli ; Comida primera: Bun Sichi Comida segunda: Hard Rock Caf'e Día 2: Manana: Ryan's ; Museu Frederic Mar'es ; Casa-Museu Gaud'i ; Tarde : Paddy Flaherty's ; Kennedy's ; Flann O'Brien ; Noche : Arcoiris ; Antilla ; La Vinya del Senyor ; Comida primera: Mas Lluhi Comida segunda: Adelita Spring Día 3: Manana: Museo de Historia de la Ciudad ; The Quiet Man ; Casa Mil'a ; Tarde : Fundaci'o Joan Mir'o ; Museu Maritim ; Cine Verdi ; Noche : The Fastnet ; Scobies ; Xampanyet ; Comida primera: Neichel Comida segunda: Al Passatore ######################################################################### ######################################################################### Viaje tranquilo: no Lugares típicos: sí Museo: sí Museo de historia: sí Museo de arte: sí Museo de Tecnología: sí Museo de personas célebres: sí Monumentos: sí Edifícios: sí Monumentos religiosos: sí Esculturas: sí Teatro: sí Teatro clásico: sí Teatro de improvisación: sí Teatro alternativo: sí Cine: sí Cine original: Cine famoso: sí Cine alternativo: sí Bares: sí español: sí irlandeses: para extranjeros: de cocktails: Comida: sí Bares para comer: sí Precio: sí sólo: sí Edad mínima: 56 Edad máxima: 56 Duración: 2 Días: 3 Día 1: Manana: Ryan's ; Museu Frederic Mar'es ; Casa Mil'a ; Tarde : Fundaci'o Joan Mir'o ; Museu Maritim ; Cine Verdi ; Noche : Ginger ; Forty ; The Fastnet ; Comida primera: Almirall Comida segunda: 'Acido 'Oxido Día 2: Manana: Museo de Historia de la Ciudad ; The Quiet Man ; Museu Egipci ; Tarde : La Vinya del Senyor ; AMC Cines Diagonal Mar ; Bodas ; Noche : Mirablau ; Rep'ublica ; Blank ; Comida primera: Antilla Comida segunda: Antic Teatre D'ia 3: Manana: Tibidabo ; Montserrat ; Museu Etnol'ogic ; Tarde : Cines Icaria Yelmo Cineplex ; Imax Port Vell ; East 47 ; Noche : Bar Marsella ; Magic ; Dry Martini ; Comida primera: Neichel Comida segunda: Arcoiris ######################################################################### ######################################################################### Viaje tranquilo: no Lugares típicos: no Museo: no Museo de historia: Museo de arte: Museo de Tecnología: Museo de personas célebres: Monumentos: no Edifícios: Monumentos religiosos: Esculturas: Teatro: no Teatro clásico: Teatro de improvisación: Teatro alternativo: Cine: no Cine original: Cine famoso: Cine alternativo: Bares: no español: irlandeses: para extranjeros: de cocktails: Comida: no Bares para comer: Precio: no sólo: sí Edad mínima: 45 Edad máxima: 45 Duración: 2 Días: 4 Día 1: Manana: Montserrat ; Casa Mil'a ; Museu d'Art Contemporani ; Tarde : Antilla ; Antic Teatre ; Ambar ; Noche : Almirall ; 'Acido 'Oxido ; Palau de la M'usica Catalana ; Comida primera: Reno Comida segunda: Bestial Día 2: Manana: Museu Etnol'ogic ; Museu Egipci ; Museu d'Arqueologia de Catalunya ; Tarde : Scobies ; Paddy Flaherty's ; Kennedy's ; Noche : Flann O'Brien ; Arcoiris ; Auditori ; Comida primera: Bun Sichi Comida segunda: Hard Rock Caf'e Día 3: Manana: Ryan's ; Museu Frederic Mar'es ; Museu Barbier-Mueller d'Art Precolombi ; Tarde : East 47 ; Dry Martini ; Bodas ; Noche : Blank ; The Fastnet ; Teatre Grec ; Comida primera: Mas Lluhi Comida segunda: Adelita Spring Día 4: Manana: Museo de Historia de la Ciudad ; The Quiet Man ; Casa-Museu Gaud'i ; Tarde : Fundaci'o Joan Mir'o ; Museu Maritim ; Cine Verdi ; Noche : Ginger ; Forty ; Teatre de Lliure ; Comida primera: Neichel Comida segunda: Al Passatore ######################################################################### ######################################################################### Viaje tranquilo: sí Lugares típicos: no Museo: Museo de historia: Museo de arte: Museo de Tecnología: Museo de personas célebres: Monumentos: Edifícios: Monumentos religiosos: Esculturas: Teatro: no Teatro clásico: Teatro de improvisación: Teatro alternativo: Cine: no Cine original: Cine famoso: Cine alternativo: Bares: sí español: sí irlandeses: sí para extranjeros: sí de cocktails: sí Comida: sí Bares para comer: sí Precio: no sólo: sí Edad mínima: 45 Edad máxima: 45 Duración: 2 Días: 4 Día 1: Manana: Museu Etnol'ogic ; Museu Egipci ; Casa-Museu Gaud'i ; Tarde : Fundaci'o Joan Mir'o ; Museu Maritim ; East 47 ; Noche : Dry Martini ; Bodas ; Scobies ; Comida primera: Antic Teatre Comida segunda: Almirall Día 2: Manana: Ryan's ; Museu Frederic Mar'es ; Casa Mil'a ; Tarde : Kennedy's ; Xampanyet ; Cine Verdi ; Noche : Ginger ; Forty ; The Fastnet ; Comida primera: Arcoiris Comida segunda: Antilla Día 3: Manana: Museo de Historia de la Ciudad ; The Quiet Man ; Montserrat ; Tarde : Blank ; Ambar ; Flann O'Brien ; Noche : La Vinya del Senyor ; Bodas ; Blank ; Comida primera: Neichel Comida segunda: Reno ######################################################################### ######################################################################### Viaje tranquilo: sí Lugares típicos: no Museo: Museo de historia: Museo de arte: Museo de Tecnología: Museo de personas célebres: Monumentos: Edifícios: Monumentos religiosos: Esculturas: Teatro: no Teatro clásico: Teatro de improvisación: Teatro alternativo: Cine: no Cine original: Cine famoso: Cine alternativo: Bares: sí español: sí irlandeses: sí para extranjeros: sí de cocktails: sí Comida: sí Bares para comer: no rápida: sí turca: sí japonesa: sí mexicana: sí china: sí italiana: sí española: sí Precio: no sólo: sí Edad mínima: 34 Edad máxima: 34 Duración: 2 Días: 2 Día 1: Manana: Ryan's ; Museu Frederic Mar'es ; Museu Egipci ; Tarde : Kennedy's ; Xampanyet ; Fundaci'o Joan Mir'o ; Noche : Cine Verdi ; Ginger ; East 47 ; Comida primera: Adelita Spring Comida segunda: Bun Sichi Día 2: Manana: Museo de Historia de la Ciudad ; The Quiet Man ; Museu Etnol'ogic ; Tarde : Blank ; Ambar ; Flann O'Brien ; Noche : La Vinya del Senyor ; Bodas ; Forty ; Comida primera: Neichel Comida segunda: Mas Lluhi ```