martes, 13 de noviembre de 2012

Practica4

Introducción

En la practica 4 se programara un sistema adaptativo relacionado con agentes inteligentes.

Agentes cooperativos: para que un agente pueda ser auto suficiente y conocedor del entorno en el que se encuentra, debe coordinarse y cooperar con cada uno de los otros agentes. Existen varias formas para hacer esto.

Tomando en cuenta El problema de el dilema del prisionero el agente i logrará tomar una decisión



Objetivo.

El objetivo de este problema es programar los agentes para los prisioneros y que estos  puedan decir que se tiene que contestar.

Para esto ninguno de los dos agentes se podrán comunicar, pero sus decisiones tendrán como efecto que queden encarcelados cierto tiempo o si quedaran en libertad. Se buscara la decisión mas apta para que cada prisionero pueda decidir su respuesta tomando en cuenta las posibilidades que se tienen, y al final se le dictara las sentencias.   



  •  Se les dice lo siguiente:
  •  Si uno confiesa y el otro no, al que confesó se le dejará libre y al otro se le encerrará por 3 años.
  •  Si ambos confiesan, los encierran por 2 años.
  •  Si ninguno confiesa, los encierran por 1 año



Justificación

Programaremos este sistema para poner así en práctica lo visto en clase, y utilizaremos precisamente un ejemplo visto ahí, que es “El dilema del prisionero” y veremos lo sucedido después de que ambos tomen su decisión. Al realizar esta práctica nosotros ya seremos capaces de realizar y comprender el mundo de los multi-agentes, lo cual nos ayudara de gran manera a ampliar nuestros conocimientos en los sistemas adaptativos. Quisimos empezar con algo no tan complejo, como una toma de decisión, en la que influye otro agente para su ganancia. De igual forma, esta práctica nos ayudara de manera considerable para la realización de nuestros proyectos finales.



 Desarrollo
El programa consiste en una sola clase llamada multiagente. En ella se crean dos objetos, que son los prisioneros  que están en la cárcel. Ambos agentes inician con una utilidad de 0. Si uno tomará una decisión, se le asigna el único método de la clase el cual se llama acción. Donde el agente, Evalúa cada una de las posibilidades de su decisión y  la de su compañero. Si la utilidad es mayor a la que conserva actualmente. Opta por quedarse con la decisión que le proporcione mas utilidad, si es caso contrario, la descarta y pasa a la siguiente posibilidad.















Código

class Multiagente:
    def __init__(self):
    
        self.accion1="confiesa" #  ambos objetos tienen dos opciones, confesar o no confesar
        self.accion2="no confiesa"
        self.utilidad=0
    def accion(self):
        # el agente pasa por el metodo accion donde evalua las posibles convinaciones y 
        # solo toma en cuenta la accion  donde la utilidad sea mayor desde donde comenzo
        #  en este caso, 0
        if agentei.accion1 and agentej.accion1:  # si ambos confiesan ambos tienen una utilidad de 2
            utilidadnueva=2
            if utilidadnueva>self.utilidad:
                print "si el agente i : ", agentei.accion1
                print "y el agente j: ", agentej.accion1
                self.utilidad=utilidadnueva
                if agente == "i":
                    print "El agente", agente, "tiene una utilidad de : ", agentei.utilidad
                    print "Entonces el agente ", agente, agentei.accion1
                if agente == "j":
                    print "El agente", agente, "tiene una utilidad de : ", agentej.utilidad
                    print "Entonces el agente ", agente, agentej.accion1
        

#si ambos no confiensan obtienen utilidades iguales de 3
        if agentei.accion2 and agentej.accion2:  
            utilidadnueva=3
            if utilidadnueva > self.utilidad:
                print "si el agente i : ", agentei.accion2
                print "y el agente j: ", agentej.accion2
                self.utilidad=utilidadnueva
                if agente == "i":
                    print "El agente", agente, "tiene una utilidad de : ", agentei.utilidad
                    print "Entonces el agente ", agente,agentei.accion2
                if agente == "j":
                    print "El agente", agente, "tiene una utilidad de : ", agentej.utilidad
                    print "Entonces el  agente ", agente, agentej.accion2
     
            
                
#utilidad 5 agente i
        if agentei.accion1 and agentej.accion2:  # si el agente confiesa y el otro no, la utilidad que recibira es 5
            utilidadnueva=5
            if agente =="j":
                utilidadnueva=0
            if utilidadnueva>self.utilidad:  
                print "si el agente i : ", agentei.accion1
                print "y el agente j: ", agentej.accion2
                self.utilidad=utilidadnueva
                if agente == "i":
                    print "El agente", agente, "tiene una utilidad de : ", agentei.utilidad
                    print "Entonces el agente ", agente,  agentei.accion1
                if agente == "j":
                    print "El agente", agente, "tiene una utilidad de : ", agentej.utilidad
                    print "Entonces el  agente ", agente, agentej.accion1
            
          
                
            
        if agentei.accion2 and agentej.accion1: # si el agente decide no  confiesar, pero el otro si, se le asigna utilidad de 0
            utilidadnueva=0
            if agente =="j":
                utilidadnueva=5
            if utilidadnueva> self.utilidad:
                print "si el agente i : ", agentei.accion2
                print "y el agente j: ", agentej.accion1
                self.utilidad=utilidadnueva
                if agente == "i":
                    print "El agente", agente, "tiene una utilidad de : ", agentei.utilidad
                    print "Enonces el agente ", agente, agentei.accion2
                if agente == "j":
                    print "El agente", agente, "tiene una utilidad de : ", agentej.utilidad
                    print "Entonces el agente ", agente,agentej.accion1
                
            #utilidad 5 agente j

        
        
        print "El mejor caso seria el ultimo donde la utilidad seria: " , self.utilidad
        
        
                
     


agentei = Multiagente() # se  el objeto agente i
agentej = Multiagente()# se crea el objeto agente j
utilidad=0

agente =str(raw_input(" Ingrese el agente que debe tomar la desicion ( i o j ): "))
while agente != "i" and agente != "j":  # se recibe el agente que tomara la decision
    agente =str(raw_input(" Ingrese el agente que debe tomar la desicion ( i o j ): "))
print "La utilidad del agente", agente, "comienza en: ", utilidad
# las utilidades de los agentes comienzan en 0

print


if agente == "i":
    # el agente i tomara la decision
    agentei.accion()

elif agente=="j":
    # el agente j tomara la decision
    agentej.accion()



Resultados.
A continuación se presentan los resultados. Donde el agente seleccionado toma la decisión que le conviene Tomo dos veces la decisión confesar... y la ultima le convendría más, ya que esa sería la mayor utilidad que podría llegar a obtener.


Video:
practica4




Conclusiones:

En esta practica se relaciono con el tema visto en clase de multiagentes. Se "simulo", la situación del problema ya descrito. Los agentes Continuamente están realizando procesos, las preferencias de los agentes se basan en su función de utilidad. Algunas mejoras futuras, seria crear un sistema de multiagentes que interactuen entre sí y puedan realizar mas de una tarea o decisión.

jueves, 1 de noviembre de 2012

Practica


Practica 3

Programación de Sistemas Adaptativos



Introducción

Para la practica 3 se   programaron dos  sistemas adaptativos relacionados con técnicas de sistemas inteligentes.

En este caso se programará un Ejemplo de RNA y Solución de problemas mediante búsqueda.

¿Qué son las redes neuronales artificiales?

Las redes de neuronas artificiales (denominadas habitualmente como RNA o en inglés como: "ANN"1 ) son un paradigma de aprendizaje y procesamiento automático inspirado en la forma en que funciona el sistema nervioso de los animales. Se trata de un sistema de interconexión de neuronas en una red que colabora para producir un estímulo de salida. En inteligencia artificial es frecuente referirse a ellas como redes de neuronas o redes neuronales.

Una red neuronal se compone de unidades llamadas neuronas. Cada neurona recibe una serie de entradas a través de interconexiones y emite una salida. Esta salida viene dada por tres funciones:

1.         Una función de propagación (también conocida como función de excitación), que por lo general consiste en el sumatorio de cada entrada multiplicada por el peso de su interconexión (valor neto). Si el peso es positivo, la conexión se denomina excitatoria; si es negativo, se denomina inhibitoria.

2.         Una función de activación, que modifica a la anterior. Puede no existir, siendo en este caso la salida la misma función de propagación.

3.         Una función de transferencia, que se aplica al valor devuelto por la función de activación. Se utiliza para acotar la salida de la neurona y generalmente viene dada por la interpretación que queramos darle a dichas salidas. Algunas de las más utilizadas son la función sigmoidea (para obtener valores en el intervalo [0,1]) y la tangente hiperbólica (para obtener valores en el intervalo [-1,1]).

El tipo de RNA que se desea simular es un perceptrón

El perceptrón  fue el primer modelo de Red Neuronal Artificial supervisada. Es la más simple de las Redes neuronales.

Sirve únicamente para problemas linealmente separables y que sean de dos clases. Hablando vulgarmente, esto quiere decir que el perceptrón sólo lo podemos usar cuando el problema sea distinguir entre una de dos posibles clases y, que trazando una línea, plano o hiperplano en un plano o hiperplano, se puedan separar perfectamente estas dos clases.

Objetivo



En esta práctica lograremos simular las propiedades observadas en los sistemas neuronales biológicos a través de modelos matemáticos recreados mediante mecanismos artificiales

Se entrenará un Perceptrón Simple para que aprenda a realizar la operación OR binaria.

Utilizar la técnica de resolución de problemas mediante búsqueda, es resolver el problema de las ocho reinas de un ajedrez, y así muestre la solución mejor o más cercana a esta. 



Justificación

¿Por qué estos  temas seleccionados ?

Las redes neuronales tienen  un aprendizaje Adaptativo, y esto es muy interesante ya que se caracterizan por su capacidad de aprender a realizar tareas basadas en un entrenamiento o en una experiencia inicial.



En Solución de problemas mediante búsqueda se manejó  un ejemplo intresante, por ser de un juego tan complejo como el ajedrez. Querer acomodar 8 reinas en un solo tablero es algo interesante por sus tipo de movimientos, por esto mismo se escogió resolver este problema por esta técnica.

Desarrollo
El perceptron programado consiste en dos capas de neuronas, una de entrada y otra de salida, Las entradas son discretas, y la función de activación de las neuronas de la capa de salida es de tipo escalón.
El ejemplo contiene dos entradas, el perceptron puede discriminar entre dos clases linealmente separables.
La operación efectuada por el perceptron consiste en :



El el caso de Solución se problemas mediante búsqueda  el sistema adaptativo  se realizo en Java, en el cual se resuelve el problema de las 8 Reinas. El cual busca colocar el mayor numero de reinas en el tablero, para esto no solo son 8 reinas en este caso es para resolver el problema con N reinas en un tablero.
Cuando empieza a ejecutarse va colocando las reinas en el tablero de manera que no se cruce con alguna otra, si las que se quieren acomodar tiene solución se colocan, si no solo coloca el numero que mejor presente solución.

Se muestra en un tablero impreso de puros “0” y en cada posición de la reina se coloca un numero del 1 al N que se ingreso, sin repetirse y sobretodo sin cruzarse una con otra.
También menciona cuantas reinas se pudieron colocar, o si se pudieron colocar todas las ingresadas.


Código:
Código Red Neuronal Artificial - Python 


import random
import math

class RNA:
     
    def __init__(self,Lp, Lpn, Lsn, ta,Lr, Lrd, Fa):
        print "                      RED NEURONAL ARTIFICIAL FUNCION OR        "
        print
        print 
        self.Lista_pesos=Lp 
        self.tasa_aprendizaje=ta
        self.Lista_primer_numero=Lpn
        self.Lista_segundo_numero=Lsn
        self.Lista_resultados=Lr
        self.Lista_resultado_deseado=Lrd
        self.Funcion_activacion=Fa
        
    def asignacion(self): #metodo para asignar las pesos de forma aleatoria
       
        
        for i in range(0,3):
            Lista_pesos.append(random.randint(0, 1))
        
        print "Lista de pesos Iniciales: ", Lista_pesos # impresion de pesos iniciales asignados
    
    def calculo_salida(self,y, Lista_resultados, Funcion_activacion):
        # metodo que calcula la salida de la red neuronal y lo almacena en una lista
        for i in range(0,4):
            
            Lista_resultados.append((Lista_pesos[1]*Lista_primer_numero[i]+Lista_pesos[2]*Lista_segundo_numero[i])+y)
            Funcion_activacion.append(Lista_resultados[i])
        print"Salidas obtenidas: ", Lista_resultados
        for i in range(0,4): # recorrido de la lista obtenida  
            # calculo de la funcion, para el caso del OR 
            if(Lista_resultados[i]>=0):
                Funcion_activacion[i]=1
            else:
                Funcion_activacion[i]=0
        # salida que obtiene el perceptron
        print"Funcion activacion, Valores de U: ", Funcion_activacion
        # si la salida no es la esperada , aui se actualizan los pesos
        if(Funcion_activacion!=Lista_resultado_deseado):
            print "El resultado no es correcto. hay que actualizar pesos"
            print 
            
            red.actualizar_pesos(Funcion_activacion)
             
        else: # cuando se  llega a la salida esperada...
            print "Los pesos adecuados son:", Lista_pesos
            print "las salidas  ya son correctas :)"
        
        
    def calcular_resultado_deseado(self):
        for i in range(0,4): #obtenemos las salidas de la funcion or 
            Lista_resultado_deseado.append(Lista_primer_numero[i] or Lista_segundo_numero[i])
        print "SALIDAS CORRECTAS DE LA FUNCION ",Lista_resultado_deseado
        
    
    def funcion(self, Funcion_activacion):
        
        for i in range(0,4):
            Funcion_activacion.append(Lista_resultados[i])
        
    def actualizar_pesos(self, Funcion_activacion):
        
# se actualizan pesos,
        for i in range(0,4):
            if(Funcion_activacion[i]!=Lista_resultado_deseado[i]):
                Lista_pesos[0]=Lista_pesos[0]+0.1*(x0)*(Lista_resultado_deseado[i]-Funcion_activacion[i])
                Lista_pesos[1]=Lista_pesos[1]+0.1*Lista_primer_numero[i]*(Lista_resultado_deseado[i]-Funcion_activacion[i])
                Lista_pesos[2]=Lista_pesos[2]+0.1*Lista_segundo_numero[i]*(Lista_resultado_deseado[i]-Funcion_activacion[i])
        
        print "peso w0 modificado",Lista_pesos[0]
        print "peso w1 modificado",Lista_pesos[1]
        print "peso w2 modificaco",Lista_pesos[2]
        print 
        print
        y=x0*Lista_pesos[0]
        Lista_resultados=[]
        Funcion_activacion=[]
        red.calculo_salida(y, Lista_resultados, Funcion_activacion)
        # se vuelve a calcular la salida con pesos nuevos
       
Lista_nuevas_salidas=[]
Lista_pesos=[]
Lista_primer_numero=[0,0,1,1] #entradas establecidas 
Lista_segundo_numero=[0,1,0,1]
Lista_resultados=[]
Lista_resultado_deseado=[]
Funcion_activacion=[]

x0=-1 
# se crea el objeto red  
red=RNA(Lista_pesos, Lista_primer_numero, Lista_segundo_numero,0.3, Lista_resultados, Lista_resultado_deseado, Funcion_activacion)  
red.asignacion()
red.calcular_resultado_deseado()
y=x0*Lista_pesos[0]
red.calculo_salida(y, Lista_resultados,Funcion_activacion)
print "Lista de resultado deseado", Lista_resultado_deseado


Código solución de problemas mediante búsqueda.

import java.util.Scanner;
 import java.util.Random;

 public class NReinas{
 Scanner entrada = new Scanner(System.in);
 Random aleatorio = new Random();
 private int Tamano;
 private int FracasosRequeridos = 1000;
 private int dado1;
 private int dado2;
 private int contadorReinas = 0;


 public void Principal(){ 
     int accesibilidad;
     
     System.out.println("\nPrograma para resolver el problemas de las 8 Reinas...");
     System.out.print("\nIntroducir el numero de casillas del tablero :D\n");
     Tamano = entrada.nextInt();
     int fracasos = 0;
     int A[][] = new int[Tamano + 1][Tamano + 1];
    
     while ( Tamano > contadorReinas && fracasos < FracasosRequeridos){
         Genera_Casilla(); 
         accesibilidad =  Verifica_Posicion(A);
         if ( 0 == accesibilidad )
             fracasos++;
         else
             A[dado1][dado2] = ++contadorReinas;
     }
    
     if ( Tamano != contadorReinas)
         System.out.printf("\nSolo se colocaron %d reinas\n", contadorReinas);
     else
         System.out.printf("\nSE COLOCARON LAS %d REINAS!\n", Tamano);
    
     Imprime(A);

 }
 
 public void Genera_Casilla(){
     dado1 = aleatorio.nextInt(Tamano) + 1;
     dado2 = aleatorio.nextInt(Tamano) + 1;
 }
 
 public int Verifica_Posicion(int B[][] ){
         int estatus = 1;
     if ( 0 == B[dado1][dado2] ){
     for ( int i = 1; i <= Tamano; i++ )
     for ( int j = 1; j <= Tamano; j++ ){  
         if ( 0 != B[i][j] ){  
             if ((( dado1 == i) || (dado2 == j ))  || (Math.abs(dado1 - i) == Math.abs(dado2 - j )) ){
                 estatus = 0;
                 break;
             }
         }   
     }  
    
     }else
         estatus = 0;
     return estatus;
 }

 public void Imprime(int C[][]){ 
     for ( int k = 1; k <= Tamano; k++ ){
         for ( int j = 1; j <= Tamano; j++){
             System.out.printf("%5d", C[k][j]);
         } 
         System.out.println("\n");
     }
 }
 
 public static void main(String args[]){
 NReinas miObjeto = new NReinas();
 miObjeto.Principal(); 
 }        

}


Resultados:
a continuación se presentan  las corridas de los programas.

















Video:






Conclusiones:

La importancia en el uso de técnicas inteligentes es que nos ayudan a resolver   problemas de una manera rápida.
La importancia en el perceptron radica en que es entrenable, el algoritmo que se utilizo permite que el perceptron determine automáticamente los pesos sinápticos que logran clasificar el conjunto de patrones.