4ª Práctica: construcción de un motor de inferencia

    Se trata de construir un motor de inferencia (M.I.) en C, C++, Java, o Pascal en su defecto, que soporte únicamente el encadenamiento hacia atrás.
 

   Consulta las reglas generales de entrega de prácticas.

Texto de la práctica

    1. El motor de inferencia se basará en lógica proposicional, debiendo soportar cláusulas de Horn: es decir, las reglas sólo tienen un consecuente y todos los precedentes están relacionados por el juntor y.

    El programa debe tener un menú principal con las siguientes opciones:

Insertar <H>echo     Insertar <R>egla    <L>istado de la base de conocimiento    <E>ncadenamiento hacia atrás
Opción:

    El formato y opciones del menú son libres, pero esas opciones deben estar.

    La entrada de hechos y reglas es libre. Los hechos no tienen ningún formato especial. En cuanto a las reglas, se pueden pedir en el formato que se prefiera (incluso consecuentes y hechos por separado).

    La opción de listado debe producir la salida de los hechos tal cuál están almacenados, y las reglas con el formato:

    consecuente :- precedente1,precedente2,precedente3,...,precedenteN

    La opción de encadenamiento hacia atrás debe pedir un hecho objetivo,. y mostrar por pantalla, al final de la inferencia, si ese hecho es cierto o falso. Por ejemplo, supongamos:

Insertar <H>echo     Insertar <R>egla    <L>istado de la base de conocimiento    <E>ncadenamiento hacia atrás
Opción: L

Reglas:
a :- b,c,d

Hechos:
b
c
d

Insertar <H>echo     Insertar <R>egla    <L>istado de la base de conocimiento    <E>ncadenamiento hacia atrás
Opción: E

Introduzca Objetivo: a

El objetivo es cierto.

Insertar <H>echo     Insertar <R>egla    <L>istado de la base de conocimiento    <E>ncadenamiento hacia atrás
Opción: L

Reglas:
a :- b,c,d

Hechos:
b
c
d
a


 

    En cuanto al diseño de la práctica, se aconseja que se diseñe una estructura llamada hecho. Una regla no es más que un hecho actuando como consecuente, más un conjunto indeterminado de hechos actuando como precedentes. Puede utilizarse, por ejemplo, un vector con un tope de 20 precedentes para implementar esto, aunque, por supuesto, lo más correcto sería un vector dinámico de precedentes.

    Para guardar los hechos y las reglas, es posible utilizar un vector dinámico separado para cada una de estas dos tipos de datos.

    En cuanto al algoritmo de encadenamiento hacia atrás, sólo debe ocuparse de confirmar o no una regla según sus precedentes existan en la base de reglas o no.

    atras(objetivo:hecho):boolean

        dev <- true

        if (not(existe_hecho_en_BC(objetivo)))

           regla_obj <- busca_regla_por_consecuente(lista_reglas,objetivo)

           while (dev = true
              and num_reglas_disponibles_consecuente(lista_reglas,objetivo)<>0)

            if (regla_encontrada(regla_obj))

                n <- 0
                precs <- 0
               while (n < num_precedentes(regla_obj))
                   if (atras(precedente(regla_obj,n))
                        precs <- precs + 1
                    n <- n + 1;
               end

               if (precs<>num_precedentes(regla_obj))
                    dev <- false
                else
                    añade_hecho_BC(objetivo)

            end
            else dev <- false;

            regla_obj <- busca_sig_regla_por_consecuente(lista_reglas, objetivo);

           end
        end

       end

       return dev
    end

    La implementación del algoritmo es libre, si bien el anterior puede servir de guía.
 

    2. Introduce la siguiente regla:

                a :- a
ó
                if (a) then a.

        y encadena hacia atrás con tu MI utilizando como objetivo a. ¿ Que sucede ? Intenta resolverlo.
 

    Entregad las respuestas a las preguntas, y el código fuente, como práctica.