Considere un sistema basado en reglas que realiza inferencia mediante encadenamiento hacia atrÁs. Los hechos ciertos se almacenan en una lista asignada a la variable *hechos*: (defvar *hechos* ‘(A H J M) ) y las reglas en otra lista asignada a la variable *reglas*: (defvar *reglas* ‘( ( (A H) (C) ) ( (C D R) (L) ) ( (B J) (C) ) ( (J M) (D) ) ( (D A) (R) ) ) ) donde cada regla consta de dos sublistas. La primera sublista almacena el antecedente: conjunto de condiciones que se deben cumplir conjuntamente para que la regla pueda ser aplicada. La segunda sublista contiene el consecuente: hecho que pasa a ser cierto cuando la regla sea ejecutada. En un proceso de encadenamiento hacia atrÁs, aquel hecho cuya veracidad pretendamos verificar da lugar a un Árbol Y-O en funciÓn del contenido de *reglas*. Por ejemplo, > (arbol-YO ‘R) (enlaceY (enlaceY J M) A) > (arbol-YO ‘L) (enlaceY (enlaceO (enlaceY A H) (enlaceY B J)) (enlaceY J M) (enlaceY (enlaceY J M) A)) > (arbol-YO ‘A) A Por tanto, cualquier Árbol Y-O generado en un proceso de encadenamiento hacia atrÁs no contendrÁ ningÚn hecho que pertenezca al consecuente de una regla perteneciente a *reglas*. Se pide, en primer lugar, escribir el procedimiento LISP, denominado “arbol-YO”, que calcule el Árbol Y-O asociado a cierto hecho, teniendo en cuenta el contenido de *reglas*. En segundo lugar, dado un Árbol Y-O cualquiera, no generado necesariamente a partir de *reglas*, construir un procedimiento LISP, denominado “evaluar-arbol-YO”, que determine si el hecho asociado a ese Árbol puede o no ser considerado como cierto en funciÓn del contenido de *hechos*. Por ejemplo, > (evaluar-arbol-YO ‘(enlaceY A H)) T > (evaluar-arbol-YO ‘(enlaceO A B)) T > (evaluar-arbol-YO ‘K) NIL > (evaluar-arbol-YO ‘(enlaceY (enlaceO A K) A M)) T SOLUCI³N (por Severino FernÁndez GalÁn): (defvar *hechos* '(A H J M)) (defvar *reglas* '(((A ((C ((B ((J ((D H) (C)) D R) (L)) J) (C)) M) (D)) A) (R)))) ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;; Procedimiento pedido en la primera parte del enunciado (defun arbol-YO (hecho) (case (numero-de-reglas-con-consecuente hecho) (0 hecho) (1 (arbol-YO-de-antecedente (antecedente-1 hecho))) (otherwise (arbol-YO-de-antecedentes (antecedentes hecho))))) ;;; Determina el número de reglas en *reglas* cuyo consecuente es "h" ;;; Ejemplo: > (numero-de-reglas-con-consecuente 'C) ;;; 2 (defun numero-de-reglas-con-consecuente (h) (let ((resultado 0)) (dolist (regla *reglas* resultado) (when (eq (caadr regla) h) (setf resultado (1+ resultado)))))) ;;; Devuelve el antecedente de la primera regla en *reglas* cuyo consecuente es "h" ;;; Ejemplo: > (antecedente-1 'C) ;;; (A H) (defun antecedente-1 (h) (dolist (regla *reglas*) (when (eq (caadr regla) h) (return (first regla))))) ;;; Halla el árbol Y-O determinado en *reglas* por los hechos de un único antecedente ;;; Ejemplo: > (arbol-YO-de-antecedente '(D A)) ;;; (enlaceY (enlaceY J M) A) (defun arbol-YO-de-antecedente (antecedente) (if (= (length antecedente) 1) (arbol-YO (first antecedente)) (let ((resultado '(enlaceY))) (dolist (hecho antecedente (reverse resultado)) (setf resultado (cons (arbol-YO hecho) resultado)))))) ;;; Devuelve una lista con los antecedentes en *reglas* cuyo consecuente es "h" ;;; Ejemplo: > (antecedentes 'C) ;;; ((A H) (B J)) (defun antecedentes (h) (let ((resultado)) (dolist (regla *reglas* resultado) (when (eq (caadr regla) h) (setf resultado (cons (first regla) resultado)))))) ;;; Halla el árbol Y-O determinado en *reglas* por la disyunción de varios antecedentes ;;; Ejemplo: > (arbol-YO-de-antecedentes '((D A) (A H))) ;;; (enlaceO (enlaceY (enlaceY J M) A) (enlaceY A H)) (defun arbol-YO-de-antecedentes (lista-de-antecedentes) (let ((resultado '(enlaceO))) (dolist (antecedente lista-de-antecedentes (reverse resultado)) (setf resultado (cons (arbol-YO-de-antecedente antecedente) resultado))))) ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;; Procedimiento pedido en la segunda parte del enunciado (defun evaluar-arbol-YO (arbol) (cond ((null arbol) nil) ((atom arbol) (member arbol *hechos*)) ((eq (first arbol) 'enlaceY) (dolist (condicion (rest arbol) t) (unless (evaluar-arbol-YO condicion) (return nil)))) ((eq (first arbol) 'enlaceO) (dolist (condicion (rest arbol) nil) (when (evaluar-arbol-YO condicion) (return t)))))) Escriba un procedimiento LISP que solicite al usuario dos matrices numÉricas, las multiplique y muestre el resultado en pantalla de manera que cada fila de la matriz resultante aparezca en un renglÓn y se reserven 7 espacios para escribir cada nÚmero. SOLUCI³N (por Severino FernÁndez GalÁn): (defun multiplica2matrices (&aux matriz1 filas1 columnas1 matriz2 columnas2 matriz3) ;; Definición de las dimensiones de las matrices (format t "~%Introduzca el número de filas de la primera matriz: ") (setf filas1 (read)) (format t "~%Introduzca el número de columnas de la primera matriz: ") (setf columnas1 (read)) (format t "~%Introduzca el número de columnas de la segunda matriz: ") (setf columnas2 (read)) ;; Definición de las matrices (setf matriz1 (make-array (list filas1 columnas1))) (setf matriz2 (make-array (list columnas1 columnas2))) (dotimes (f1 filas1) (dotimes (c1 columnas1) (format t "~%Escriba elemento (~a,~a) de la primera matriz: " (1+ f1) (1+ c1)) (setf (aref matriz1 f1 c1) (read)))) (dotimes (f2 columnas1) (dotimes (c2 columnas2) (format t "~%Escriba elemento (~a,~a) de la segunda matriz: " (1+ f2) (1+ c2)) (setf (aref matriz2 f2 c2) (read)))) ;; Calcular la matriz resultante (setf matriz3 (make-array (list filas1 columnas2))) (dotimes (f3 filas1) (dotimes (c3 columnas2) (let ((parcial 0)) (dotimes (n columnas1) (setf parcial (+ parcial (* (aref matriz1 f3 n) (aref matriz2 n c3))))) (setf (aref matriz3 f3 c3) parcial)))) ;; Mostrar resultado poniendo cada fila en un renglón (format t "~%Matriz resultante de la multiplicación de las dos anteriores: ") (dotimes (f3 filas1) (format t "~%") (dotimes (c3 columnas2) (format t "~7a" (aref matriz3 f3 c3)))) )