jueves, 20 de septiembre de 2018

Implementación del método de ordenación HeapSort en Golang

Implementación del método de ordenación HeapSort en Golang
MÉTODO DE ORDENACIÓN HEAPSORT


Este algoritmo consiste en almacenar todos los elementos del vector a ordenar en un montículo (heap), y luego extraer el nodo que queda como nodo raíz del montículo (cima) en sucesivas iteracciones obteniendo el conjunto ordenado. Basa su funcionamiento en una propiedad de los montículos, por la cual, la cima contiene siempre el menor elemento (o el mayor, según se haya definido el montículo) de todos los almacenados en él. El algoritmo, después de cada extracción, re coloca en el nodo raíz o cima, la última hoja por la derecha del último nivel. Lo cual destruye la propiedad heap del árbol. Pero, a continuación realiza un proceso de "descenso" del número insertado de forma que se elige a cada movimiento el mayor de sus dos hijos, con el que se intercambia. Este intercambio, realizado sucesivamente "hunde" el nodo en el árbol restaurando la propiedad montículo del árbol y dejando paso a la siguiente extracción del nodo raíz.


Implementación


package main

import "fmt"

func main() {
 var ListaDesordenada = []int{15, 3, 8, 6, 18, 1}
 ListaOrdenada := heapSort(ListaDesordenada)
 fmt.Println(ListaOrdenada)
}

// METODO DE ORDENACION: HEAP SORT
func heapSort(ListaDesordenada []int) []int {
 var ListaOrdenada = []int{}
 N := len(ListaDesordenada)
 for nodo := N / 2; nodo >= 0; nodo-- {
  ListaOrdenada = doHeapSort(ListaDesordenada, nodo, N-1)
 }
 for nodo := N - 1; nodo >= 0; nodo-- {
  tmp := ListaDesordenada[0]
  ListaDesordenada[0] = ListaDesordenada[nodo]
  ListaDesordenada[nodo] = tmp
  ListaOrdenada = doHeapSort(ListaDesordenada, 0, nodo-1)
 }
 return ListaOrdenada
}
func doHeapSort(ListaDesordenada []int, nodo int, fin int) []int {
 izq := 2*nodo + 1
 der := izq + 1
 var may int
 if izq > fin {
  return ListaDesordenada
 }
 if der > fin {
  may = izq
 } else {
  if ListaDesordenada[izq] > ListaDesordenada[der] {
   may = izq
  } else {
   may = der
  }
 }
 if ListaDesordenada[nodo] < ListaDesordenada[may] {
  tmp := ListaDesordenada[nodo]
  ListaDesordenada[nodo] = ListaDesordenada[may]
  ListaDesordenada[may] = tmp
  doHeapSort(ListaDesordenada, may, fin)
 }
 return ListaDesordenada
}

Espero les sea de utilidad y hasta la próxima.

Implementación del método de ordenación MergeSort en Golang

La tarea de la programación esta ligada al objetivo de obtener algoritmos que resuelvan un problema con la mayor eficiencia posible; de hecho es sorprendente comprobar las múltiples formas como podemos resolver un mismo problema y las ventajas que conseguimos , en términos de eficiencia , al buscar soluciones alternativas a las ya conocidas o consideradas como evidentes.
Para comparar y analizar la eficiencia de los algoritmos , estos los consideramos escritos en un lenguaje de programación de alto nivel , pero aun empleando la misma representación , establecer una medida precisa de la eficiencia de un algoritmo no es fácil.En efecto , fijémonos en que una definición de eficiencia podría ser el numero de instrucciones que tiene el programa ; sin embargo esto no se correspondería , con el concepto intuitivo que tenemos de eficiencia(según el cual,el algoritmo mas eficiente seria aquel que tardase menos tiempo en resolver el problema sobre una misma maquina), dado que todas las instrucciones no utilizan el mismo tiempo de procesador aun realizando la misma función.

MÉTODO DE ORDENACIÓN MERGESORT:
Este algoritmo consiste básicamente en dividir en partes iguales la lista de números y luego mezclarlos comparándolos, dejándolos ordenados.
Si se piensa en este algoritmo recursivamente, podemos imaginar que dividirá la lista hasta tener un elemento en cada lista, luego lo compara con el que está a su lado y según corresponda, lo sitúa donde corresponde.
En la siguiente figura podemos ver cómo funciona:



Implementación


package main

import "fmt"

//METODO DE ORDENACION: MERGESORT
func main() {
 var ListaDesordenada = []int{15, 3, 8, 6, 18, 1}
 ListaOrdenada := mergeSort(ListaDesordenada, 0, len(ListaDesordenada)-1)
 fmt.Println(ListaDesordenada)
}
func mergeSort(ListaDesordenada []int, iMin int, iMax int) []int {
 // Caso Base
 if iMin >= iMax {
  return ListaDesordenada
 }
 // Cortamos para aplicar mergeSort recursivamente
 k := (iMin + iMax) / 2
 mergeSort(ListaDesordenada, iMin, k)
 mergeSort(ListaDesordenada, k+1, iMax)
 // Utilizamos un arreglo temporal
 l := iMax - iMin + 1
 var temp = []int{}
 for i := 0; i < l; i++ {
  temp[i] = ListaDesordenada[iMin+i]
 }
 // Mezclamos
 i1 := 0
 i2 := k - iMin + 1
 for i := 0; i < l; i++ {
  if i2 <= iMax-iMin {
   if i1 <= k-iMin {
    if temp[i1] > temp[i2] {
     ListaDesordenada[i+iMin] = temp[i2+1]
    } else {
     ListaDesordenada[i+iMin] = temp[i1+1]
    }
   } else {
    ListaDesordenada[i+iMin] = temp[i2+1]
   }
  } else {
   ListaDesordenada[i+iMin] = temp[i1+1]
  }
 }
 return ListaDesordenada
}

Espero que les sea de utilidad y hasta la próxima

Implementación del método de ordenación QuickSort en Golang

En computación y matemáticas un algoritmo de ordenamiento es un algoritmo que pone elementos de una lista o un vector en una secuencia dada por una relación de orden, es decir, el resultado de salida ha de ser una permutación  o reordenamiento de la entrada que satisfaga la relación de orden dada. Los ordenamientos eficientes son importantes para optimizar el uso de otros algoritmos (como los de búsqueda y fusión) que requieren listas ordenadas para una ejecución rápida. También es útil para poner datos en forma canónica y para generar resultados legibles por humanos.

MÉTODO DE ORDENACIÓN QUICKSORT:


Sin duda, este algoritmo es uno de los más eficientes. Este método es el más rápido gracias a sus llamadas recursivas, basándose en la teoría de divide y vencerás.
Lo que hace este algoritmo es dividir recursivamente el vector en partes iguales, indicando un elemento de inicio, fin y un pivote (o comodín) que nos permitirá segmentar nuestra lista. Una vez dividida, lo que hace, es dejar todos los mayores que el pivote a su derecha y todos los menores a su izquierda Al finalizar el algoritmo, nuestros elementos están ordenados.
Por ejemplo, si tenemos 3 5 4 8 básicamente lo que hace el algoritmo es dividir la lista de 4 elementos en partes iguales, por un lado 3, por otro lado 4 8 y como comodín o pivote el 5. Luego pregunta, 3 es mayor o menor que el comodín? Es menor, entonces lo deja al lado izquierda Y como se acabaron los elementos de ese lado, vamos al otro lado. 4 Es mayor o menor que el pivote? Menor, entonces lo tira a su izquierda. Luego pregunta por el 8, al ser mayor lo deja donde está, quedando algo así: 3 4 5 8.
En esta figura se ilustra de mejor manera un vector con más elementos, usando como pivote el primer elemento:


Algoritmo

// Inicialización de variables
    elem_div = lista[sup];
    i = inf - 1;
    j = sup;
    cont = 1;
    
    // Verificamos que no se crucen los límites
    if (inf >= sup)
          retornar;
    
    //  Clasificamos la sublista
    while (cont)
          while (lista[++i] < elem_div);
          while (lista[--j] > elem_div);
         if (i < j)
              temp = lista[i];
              lista[i] = lista[j];
              lista[j] = temp;
         else
              cont = 0;
   
   // Copiamos el elemento de división
   // en su posición final
    temp = lista[i];
    lista[i] = lista[sup];
    lista[sup] = temp;
   
   // Aplicamos el procedimiento
   // recursivamente a cada sublista
    OrdRap (lista, inf, i - 1);
    OrdRap (lista, i + 1, sup);
Implementación:
package main

import "fmt"

func main() {
 var ListaDesordenada = []int{15, 3, 8, 6, 18, 1}
 var N int = len(ListaDesordenada)
 ListaOrdenada := quicksort(ListaDesordenada, 0, N-1)
 fmt.Println(ListaOrdenada)
}

func quicksort(ListaDesordenada []int, izq int, der int) []int {
 pivote := ListaDesordenada[izq] // tomamos primer elemento como pivote
 i := izq                        // i realiza la búsqueda de izquierda a derecha
 j := der                        // j realiza la búsqueda de derecha a izquierda
 var aux int

 for i < j { // mientras no se crucen las búsquedas
  for ListaDesordenada[i] <= pivote && i < j {
   i++
  } // busca elemento mayor que pivote
  for ListaDesordenada[j] > pivote {
   j--
  } // busca elemento menor que pivote
  if i < j { // si no se han cruzado
   aux = ListaDesordenada[i] // los intercambia
   ListaDesordenada[i] = ListaDesordenada[j]
   ListaDesordenada[j] = aux
  }
 }
 ListaDesordenada[izq] = ListaDesordenada[j] // se coloca el pivote en su lugar de forma que tendremos
 ListaDesordenada[j] = pivote                // los menores a su izquierda y los mayores a su derecha
 if izq < j-1 {
  quicksort(ListaDesordenada, izq, j-1) // ordenamos subarray izquierdo
 }

 if j+1 < der {
  quicksort(ListaDesordenada, j+1, der) // ordenamos subarray derecho
 }
 return ListaDesordenada
}

Implementación del Método de ordenación Inserción en Golang



En computación y matemáticas un algoritmo de ordenamiento es un algoritmo que pone elementos de una lista o un vector en una secuencia dada por una relación de orden, es decir, el resultado de salida ha de ser una permutación  o reordenamiento de la entrada que satisfaga la relación de orden dada. Los ordenamientos eficientes son importantes para optimizar el uso de otros algoritmos (como los de búsqueda y fusión) que requieren listas ordenadas para una ejecución rápida. También es útil para poner datos en forma canónica y para generar resultados legibles por humanos.

MÉTODO DE ORDENACIÓN INSERCIÓN:
La idea de este algoritmo de ordenación consiste en ir insertando un elemento de la lista o un arreglo en la parte ordenada de la misma, asumiendo que el primer elemento es la parte ordenada, el algoritmo ira comparando un elemento de la parte desordenada de la lista con los elementos de la parte ordenada, insertando el elemento en la posición correcta dentro de la parte ordenada, y así sucesivamente hasta obtener la lista ordenada. Para explicarlo mejor nos basaremos en el siguiente enunciado:
“Para cada elemento de la lista después del primero, comparar los elementos con los anteriores desplazando una posición a la derecha a todos los elementos anteriores que cumplan con la comparación y luego colocar el elemento en la posición del último elemento anterior desplazado.”



Algoritmo:
for (i=1; i<TAM; i++)
      aux = array[i];
      j = i - 1;
      while ( (array[j] > aux) && (j >= 0) )
          array[j+1] = array[j];
           j--;
      array[j+1] = aux;



Implementacion:

func Insercion(ListaDesordenada []int) []int {
 var auxiliar int
 for i := 1; i < len(ListaDesordenada); i++ {
  auxiliar = ListaDesordenada[i]
  for j := i - 1; j >= 0 && ListaDesordenada[j] > auxiliar; j-- {
   ListaDesordenada[j+1] = ListaDesordenada[j]
   ListaDesordenada[j] = auxiliar
  }
 }
 return ListaDesordenada
}

Espero les sirva y hasta la próxima oportunidad

Implementación del Método de Ordenación Burbuja en Golang



En computación y matemáticas un algoritmo de ordenamiento es un algoritmo que pone elementos de una lista o un vector en una secuencia dada por una relación de orden, es decir, el resultado de salida ha de ser una permutación  o reordenamiento de la entrada que satisfaga la relación de orden dada. Los ordenamientos eficientes son importantes para optimizar el uso de otros algoritmos (como los de búsqueda y fusión) que requieren listas ordenadas para una ejecución rápida. También es útil para poner datos en forma canónica y para generar resultados legibles por humanos.


MÉTODO DE ORDENAMIENTO BURBUJA:

Este es uno de los métodos de ordenamiento mas usados .aunque no de los mas eficaces.
Consiste en recorrer la lista de valores a ordenar y compararlos dos a dos.Si los elementos están bien ordenados, pasamos al siguiente , hasta llegar al final de la lista.El proceso completo se repite hasta que la lista este ordenada.




Algoritmo:
DESDE I=1 hasta N-1 hacer
    DESDE J=1 hasta N-1 hacer
          Si v[J]>V[J+1] entonces
                Aux= V[J]
                V[J]=V[J+1]
                V[J+1]=Aux
           FIN SI
     FIN DESDE
FIN DESDE


Implementación:


func Burbuja(ListaDesordenada []int) []int {
 var auxiliar int
 for i := 0; i < len(ListaDesordenada); i++ {
  for j := 0; j < len(ListaDesordenada); j++ {
   if ListaDesordenada[i] > ListaDesordenada[j] {
    auxiliar = ListaDesordenada[i]
    ListaDesordenada[i] = ListaDesordenada[j]
    ListaDesordenada[j] = auxiliar
   }
  }
 }
 return ListaDesordenada
}

Espero les sea de utilidad y hasta la próxima oportunidad

domingo, 7 de agosto de 2016

Reconocimiento de Patrones mediante redes neuronales

RECONOCIMIENTO DE PATRONES MEDIANTE REDES NEURONALES

Hola amigos en esta ocasión les comparto una aplicación que se realizo en un curso de Inteligencia Artificial que estuve llevando en la universidad espero les sea de utilidad como es de costumbre comenzare con algo de teoría para luego compartir con ustedes el código fuente de la aplicación.

REDES NEURONALES

Una red neuronal artificial es un procesador distribuido en paralelo de forma masiva que tiene una tendencia natural para almacenar conocimiento de forma experimental y lo hace disponible para su uso.

SIMILITUD CON EL CEREBRO HUMANO:

  • El conocimiento es adquirido por la red a través de un proceso de aprendizaje.
  • Los pesos sinápticos o fuerza con que están interconectadas las neuronas se utilizan para almacenar la información.

En esta publicación se describirá una aplicación típica de las redes neuronales multicapa, concretamente el reconocimiento de patrones.

PERCEPTRÓN MULTINIVEL
Dentro de las redes neuronales, las que más utilizadas son las redes con múltiples capas que funcionan hacia delante. Esta red esta compuesta por un conjunto de nodos de entrada que componen la capa de entrada, un conjunto de una o más capas ocultas de neuronas y una capa de neuronas de salida. La señal de entrada se propaga hacia adelante desde la capa de entrada por la oculta hasta la salida; este tipo de configuración se conoce como MLP o "MultiLayer Perceptrons".


El hecho de que este tipo de red se aplique para resolver con éxito multitud de problemas se debe a la utilización del algoritmo de aprendizaje que actualmente está más extendido, el algoritmo o regla back propagation, el cual es una generalización de la regla LMS "Least Mean Square", por lo tanto también se basa en la corrección del error.
Básicamente el proceso back propagation consiste en dos pasadas a través de las diferentes capas de la red, una pasada hacia adelante y una pasada hacia atrás. En la pasada hacia adelante, se aplica en la capa de entrada un patrón o vector de entrada, este propaga su efecto a través de las diferentes capas y como consecuencia produce un vector de salida. 
Durante este proceso, los pesos sinápticos de la red son fijos y no se modifican. Durante la pasada hacia atrás en cambio, los pesos si se modifican de acuerdo con la regla de corrección del error. La señal de salida real se compara con la señal deseada y como resultado se obtiene una señal de error, que se propaga en dirección contraria a través de la red modificando los pesos, de forma que, al volver a pasar el vector de entrada hacia adelante, la respuesta obtenida se asemeje más a la salida deseada. Concretando, se puede decir que un perceptrón multicapa tiene tres características:

  • El modelo de cada neurona (figura 2) incluye una función no lineal. En este caso, a diferencia del perceptrón donde es la función escalón, y debido a la necesidad de que sea una función continua y derivable, es la función sigmoide, donde uk es la suma total de la actividad interna en la neurona k (la señal de entrada) e yk la salida que se produce en la neurona.




  • La red contiene una o más capas ocultas de neuronas que no forman parte ni de la entrada ni de la salida. Estas neuronas ocultas capacitan a la red para aprender progresivamente cualquier correspondencia entre la entrada y la salida y almacenar internamente esta información.
  • La red posee un gran número de conexiones, estas vienen determinadas por los pesos de la red. Un cambio en la conexión entre las neuronas equivale a un cambio en los pesos.
La combinación de estas características, hace que la habilidad de esta red para aprender a partir del entrenamiento sea muy potente, por ejemplo es capaz de resolver el problema de la OR-exclusiva a diferencia del perceptrón.

De todas formas, este comportamiento hace que sea difícil conocer a priori la respuesta de la red. Esto se debe a dos motivos, el comportamiento no lineal de las neuronas, las cuales están muy interconectadas, (lo que hace difícil un análisis teórico de la red) y la existencia de neuronas ocultas, que impide poder "ver" como se produce el aprendizaje y determinar cuales son las características que mejorarían el aprendizaje.

El desarrollo del algoritmo back propagation proporciona un método eficiente para entrenar este tipo de redes. Aunque no es capaz de resolver todos los problemas, se ha demostrado como el mejor de todos. Su importancia está en su capacidad de autoadaptar los pesos de las neuronas intermedias para aprender la relación que existe entre el conjunto de vectores o patrones de entrada y su correspondiente salida, y poder aplicar esa relación después del entrenamiento a nuevos vectores de entrada imperfectos o con ruido. Esta capacidad se conoce como generalización. La red debe encontrar una representación interna que le permita generar las salidas deseadas durante la etapa de entrenamiento, y posteriormente durante el funcionamiento ser capaz de generar salidas para entradas que no le fueron mostradas durante el aprendizaje pero que se asemejan a alguna de las que si le fueron mostradas.

EJEMPLO DE APLICACIÓN:

Para simular el funcionamiento de un perceptrón multinivel entrenado mediante el algoritmo back propagation, se plantea un sencillo problema de reconocimiento de óptico de caracteres. Su descripción es la siguiente:

Dado un panel de entrada compuesto por una matriz de 7x5 puntos, se consideran 12 clases diferentes donde se pretenden clasificar las muestras que se introducen. Los patrones que definen correctamente a cada una de las clases son los números del 0 al 9, el punto y el guión (figura 3).

Cuando a la entrada se presente una muestra distinta de los patrones correctos, el sistema presentará a su salida la información decodificada de la clase a la que pertenece la muestra, o bien, de la clase a la cual se aproxima más. En base a este planteamiento, la red neuronal dispone de 35 entradas que se corresponden con los puntos de la matriz numerados en la figura 4. El valor de cada entrada puede ser 0 si el punto es blanco y 1 si el punto es negro. Por otro lado, dispone de 12 salidas, una por cada clase. Cuando se introduzca una muestra a la entrada únicamente se activará la salida de la clase a la que pertenezca, permaneciendo las 11 restantes desactivadas con valores próximos a cero. Se considera que una salida está activada cuando su valor es próximo a la unidad.




RESULTADOS DE LA SIMULACIÓN:
Se realizo la implementación de una red neuronal en Java.En él se ha programado un perceptrón multinivel con 35 entradas y 12 salidas. También dispone de dos capas ocultas a las cuales se les puede modificar el número de sus neuronas. La red neuronal se ha entrenado con el algoritmo back propagation fijando el valor del momento en 0.8 y el factor de aprendizaje en 0.2. En este proceso únicamente se han usado doce muestras diferentes, es decir, los doce patrones sin ningún punto erróneo.
En la tabla I se muestran los resultados obtenidos para una red neuronal de tamaño 35-30-20-12. Se aprecia que tras el proceso de entrenamiento, el sistema responde de forma casi ideal cuando se introduce un patrón sin error.


IMPLEMENTACIÓN:






package digitos;
import javax.swing.JOptionPane;
public class digitos {

        int filas_entrada = 7;
        int col_entrada = 5;
        int neuronas_entrada = 35;
        int neuronas_oculta = 4;
        int neuronas_salida = 6;
        int i, j, k;
        int respuesta;
        int[][] patron = new int[5][7];
        double[][] pesos_entrada_oculta = {{1.658270037469468, -0.49277400626557, 0.8458827274104553, -2.648551432075224},
            {1.1603936240938337, -2.518757565059801, -0.21162501186454472, 0.4483509644280242},
            {0.9770989216075385, -1.1100683771308992, 0.5996520501870459, -1.5726273589648947},
            {-0.013373815758508401, -1.8088573544737623, -0.1806466969385013, 1.5619996308946966},
            {1.5477043440927314, -0.7451285620786131, 0.9078974238442922, -2.35721899617673},
            {1.6375625959682456, 0.05352515438526517, -1.7744239541344213, 1.4633986290892553},
            {-0.4895683338278625, 1.8177553658981087, 1.2455793786819767, -2.190482442936407},
            {-1.6471092496923165, 3.229636202454947, 1.2981497902378096, -0.7057775268591435},
            {-1.5667407635246655, -1.3245937353788448, 2.136912211349784, 0.006483361683210399},
            {-0.30620712895539964, -2.082257488430547, -0.7831144540926332, 2.860170068975273},
            {1.90730880729867, 1.786324022652642, -2.7987064218352016, -0.01985271542781151},
            {0.6073378720265543, 2.964084801890168, -0.8036519556281736, -0.11124911355434831},
            {0.8920664710707924, 1.2889968423497409, 1.4524992877441234, -4.5753301334234395},
            {0.5438102680069633, 2.732096021393861, -2.46484031199823, 1.077136757466367},
            {-0.5920084064677441, -2.0176453417628553, -0.8929972447944864, 2.9295974905024473},
            {-1.2273348838814682, 0.9665674119959388, -1.5098278165865484, 2.3855936692870223},
            {0.00303354357445883, 0.001581271588014359, 0.5078086841379089, -0.15023910421206893},
            {-0.2793511488473059, 1.4245803844405784, -0.8720662059686077, -0.5734228021484368},
            {-2.0275946046978293, -3.0777889662395226, 2.599080818031238, 1.6382349764441964},
            {1.7261757824595334, 1.8271668605813292, -2.6230163017984798, -0.023102087227872905},
            {-1.0400284786362686, 0.7483028076885504, -1.4201964658386028, 2.5893497462079242},
            {-1.2173094553360448, 1.0413190887119863, -1.3232448940438146, 2.7280471684208245},
            {-2.0889500107780266, 1.2113367713729557, 1.834844976337663, 0.48588965399759093},
            {-1.3959767352554984, 1.340974141434604, 0.4669554523335953, 0.8396877795787216},
            {0.5504882733683742, -0.007280194521717799, -1.049601349327548, 0.10628579988651637},
            {1.443454707114963, -1.1329167860893807, -1.202733639186253, -1.1206540048585907},
            {-0.4331284905557263, -1.5624137840495447, 1.116280151906849, 1.4607759610209936},
            {-0.5819930384824622, 1.758192614385909, 0.9171022839298032, -2.0753538337866986},
            {-1.3256304624056356, 1.044596834400223, 0.26717962626473013, 1.1753997160814336},
            {1.5797847092614183, -1.103413366841749, -1.1869484693704706, -1.0426817633297494},
            {-0.42533166857338317, -1.5201849827392802, 0.8863374072683927, 1.5286999085413167},
            {0.7681134972990639, -0.9328664559674184, 0.3210235342096992, -1.6081085875846808},
            {0.8656526958020259, -1.075079526248985, 0.4316305641408157, 1.4876790164633573},
            {-0.3418033974126609, 0.26137924890846875, 0.44588921383473606, -0.44772778571106026},
            {-0.5446034869269726, -1.7972802169693622, 1.143196716800601, 1.244775128422288}};
        
        
        double[][] pesos_oculta_salida = {{0.43621096542085136, -4.4770098664620495, -3.4380683245083805, 1.8296159164887345, -8.118120689656921, 5.695458556119513},
            {-1.027258581059679, 5.023126898792579, -7.757507526435068, -7.156764734520939, 4.478145059142636, 2.0603488963286387},
            {-8.390374693334456, 2.4451631927893267, 1.1247117391293466, 3.3697153535415416, -1.6716192668623555, -5.293714775954221},
            {5.151637910542471, -7.364970554525968, 4.923974784168798, -6.575339204075441, 4.552711228559867, -6.736958999045322}};
        
        
        
        double[] bias_entrada = {-0.4332161363101981,
            -0.5121521114762152,
            -0.39471528129652694,
            -0.5445351790184725,
            -0.4226637563836109,
            -0.5350195879964442,
            -0.3350043955733998,
            -0.38791367789336956,
            -0.3785593217087376,
            -0.5461130438610313,
            -0.554558738450257,
            -0.44288964426354815,
            -0.4380540832801621,
            -0.5350394221895475,
            -0.5580057611292775,
            -0.5560034483432901,
            -0.12912939908250873,
            -0.4139805211691567,
            -0.48481548633114296,
            -0.5388170156483836,
            -0.5565657646610173,
            -0.5633684138684646,
            -0.26352247776223936,
            -0.17951484914217863,
            -0.3253386781429675,
            -0.5422856630504476,
            -0.3859925425287016,
            -0.2926752007933522,
            -0.33661294128974667,
            -0.5351966380727077,
            -0.43172146451991633,
            -0.3614435550912756,
            -0.3009252579538338,
            0.13116124654486072,
            -0.42061848358615506,};
        double[] bias_oculta = {-0.5396208362695601,
            0.2293253598179893,
            0.9023280877608804,
            -0.5367884581404073};
        
        double[] bias_salida = {-1.3662965402953284,
            -2.7832950402557444,
            -1.5508290258166995,
            -0.47188562328444716,
            -4.298755314842922,
            -2.4180200713742552,};
        
        int[] entrada = new int[neuronas_entrada];
        double[] sumatoria_entrada = new double[neuronas_entrada];
        double[] sigmoidal_entrada = new double[neuronas_entrada];
        
        double[] oculta = new double[neuronas_oculta];
        double[] sumatoria_oculta = new double[neuronas_oculta];
        double[] sigmoidal_oculta = new double[neuronas_oculta];
        
        double[] salida = new double[neuronas_salida];
        double[] sumatoria_salida = new double[neuronas_salida];
        double[] sigmoidal_salida = new double[neuronas_salida];
        public digitos(int patrones[][])
        {
            this.patron=patrones;
        }
        public void reconocimiento()
        {
            //procesamiento de la capa de entrada
            //linealizar el patron de entrada
            for (i = 0; i  <  filas_entrada; i++) {
                for (j = 0; j  <  col_entrada; j++) {

                    entrada[i * col_entrada + j] = patron[i][j];
                }
            }

            //1.2 sumar la entrada con el bias y calcular sigmidal
            for (i = 0; i  <  neuronas_entrada; i++) {
                sumatoria_entrada[i] = entrada[i] + bias_entrada[i];
                sigmoidal_entrada[i] = 1 / (1 + Math.exp(-1 * sumatoria_entrada[i]));
            }
            //2. procesamiento de la capa oculta
            // 2.1 sumatoria de productos de entrada por peso
            for (j = 0; j  <  neuronas_oculta; j++) {
                oculta[j] = 0;
                for (i = 0; i  <  neuronas_entrada; i++) {
                    oculta[j] += sigmoidal_entrada[i] * pesos_entrada_oculta[i][j];
                }
            }
            //2.2 sumatoria mas bias y calculo de sigmoidal
            for (i = 0; i  <  neuronas_oculta; i++) {
                sumatoria_oculta[i] = oculta[i] + bias_oculta[i];
                sigmoidal_oculta[i] = 1 / (1 + Math.exp(-1 * sumatoria_oculta[i]));
            }

            //3. procesamiento de la capa salida
            //3.1 suamtoria de productos de salida x peso
            for (j = 0; j  <  neuronas_salida; j++) {
                salida[j] = 0;
                for (i = 0; i  <  neuronas_oculta; i++) {
                    salida[j] += sigmoidal_oculta[i] * pesos_oculta_salida[i][j];
                }
            }
            //3.2 sumatoria mas bias y calculo de sigmoidal
            for (i = 0; i  <  neuronas_salida; i++) {
                sumatoria_salida[i] = salida[i] + bias_salida[i];
                sigmoidal_salida[i] = 1 / (1 + Math.exp(-1 * sumatoria_salida[i]));
                System.out.println("Sigmoidal [" + i + "]- " + sigmoidal_salida[i]);
            }
            // 4.construyendo la interface de salida
            double mayor = -0.999;
            int neurona_activada = -1;
            for (i = 0; i  <  neuronas_salida; i++) {
                if (sigmoidal_salida[i]  >  mayor) {

                    mayor = sigmoidal_salida[i];
                    neurona_activada = i;
                }
            }
            if (mayor  >  0.80 ) { // heuristica para saber si el patron es coherente
                switch (neurona_activada) {
                    case 0:
                        respuesta=0;
                        System.out.println("RESPUESTA:"+respuesta);
                        break;
                    case 1:
                        respuesta=1;
                        System.out.println("RESPUESTA:"+respuesta);
                        break;
                    case 2:
                        respuesta=2;
                        System.out.println("RESPUESTA:"+respuesta);
                        break;
                    case 3:
                        respuesta=3;
                        System.out.println("RESPUESTA:"+respuesta);
                        break;
                    case 4:
                        respuesta=4;
                        System.out.println("RESPUESTA:"+respuesta);
                        break;
                    case 5:
                        respuesta=5;
                        System.out.println("RESPUESTA:"+respuesta);
                        break;

                }
            } else
            { 
                respuesta=-1;
                System.out.println("RESPUESTA:"+respuesta);
            }
        }
        public int getReconocimiento()
        {
            return respuesta;
        }

}


RESULTADOS OBTENIDOS EN LA IMPLEMENTACIÓN



jueves, 23 de junio de 2016

Implementación de un Sistema Experto Probabilistico EDA (Enfermedad Diarreica Aguda) usando el Teorema de Bayes con conexion a Mysql



Implementación de un Sistema Experto Probabilistico EDA (Enfermedad Diarreica Aguda)  usando el Teorema de Bayes con conexión a Mysql


El teorema de Bayes, en la teoría de la probabilidad, es una proposición planteada por el filósofo inglés Thomas Bayes (1702-1761)1 en 1763,2 que expresa la probabilidad condicional de un evento aleatorio A dado B en términos de la distribución de probabilidad condicional del evento B dado A y la distribución de probabilidad marginal de sólo A.

En términos más generales y menos matemáticos, el teorema de Bayes es de enorme relevancia puesto que vincula la probabilidad de A dado B con la probabilidad de B dado A. Es decir, que sabiendo la probabilidad de tener un dolor de cabeza dado que se tiene gripe, se podría saber (si se tiene algún dato más), la probabilidad de tener gripe si se tiene un dolor de cabeza. Muestra este sencillo ejemplo la alta relevancia del teorema en cuestión para la ciencia en todas sus ramas, puesto que tiene vinculación íntima con la comprensión de la probabilidad de aspectos causales dados los efectos observados.



DESCRIPCIÓN DEL PROBLEMA:

Un centro médico tiene una BD con las historias clínicas de N = 1000 pacientes.
Estas historias clínicas se resumen gráficamente en la figura. Hay 700 pacientes (región sombreada) que tienen la enfermedad adenocarcinoma gástrico (G), y 300 que no la tienen (se considera estar sano como otro valor posible de la enfermedad). Tres síntomas, dolor (D), pérdida de peso (P) y vómitos (V ), se considera que están ligados a esta enfermedad. Por tanto, cuando un paciente nuevo llega al centro médico, hay una probabilidad 700/1000 = 70% de que el paciente tenga adenocarcinoma gástrico. Esta es la probabilidad inicial, o “a priori”, puesto que se calcula con la información inicial, antes de conocer información alguna sobre el paciente.


Se pide crear un SEP que permita diagnosticar el nivel de probabilidad que tiene un paciente de haber adquirido esta enfermedad en base a los sintomas antes mencionados.


Base de datos:

create database Enfermedad;
use Enfermedad;
create table diagnostica(
    codigo int auto_increment primary key,
    dolor char(1),
    vomito char(1),
    p_peso char(1),
    estado char(1),
    cantidad int
);

insert into diagnostica(dolor, p_peso,vomito,estado,cantidad) values ('s','s','s','s',220);
insert into diagnostica(dolor, p_peso,vomito,estado,cantidad) values ('s','s','s','n',220);
insert into diagnostica(dolor, p_peso,vomito,estado,cantidad) values ('s','s','n','s',25);
insert into diagnostica(dolor, p_peso,vomito,estado,cantidad) values ('s','s','n','n',25);
insert into diagnostica(dolor, p_peso,vomito,estado,cantidad) values ('s','n','s','s',95);
insert into diagnostica(dolor, p_peso,vomito,estado,cantidad) values ('s','n','s','n',95);
insert into diagnostica(dolor, p_peso,vomito,estado,cantidad) values ('s','n','n','s',10);
insert into diagnostica(dolor, p_peso,vomito,estado,cantidad) values ('s','n','n','n',10);
insert into diagnostica(dolor, p_peso,vomito,estado,cantidad) values ('n','s','s','s',4);
insert into diagnostica(dolor, p_peso,vomito,estado,cantidad) values ('n','s','s','n',9);
insert into diagnostica(dolor, p_peso,vomito,estado,cantidad) values ('n','s','n','s',5);
insert into diagnostica(dolor, p_peso,vomito,estado,cantidad) values ('n','s','n','n',12);
insert into diagnostica(dolor, p_peso,vomito,estado,cantidad) values ('n','n','s','s',31);
insert into diagnostica(dolor, p_peso,vomito,estado,cantidad) values ('n','n','s','n',76);
insert into diagnostica(dolor, p_peso,vomito,estado,cantidad) values ('n','n','n','s',50);
insert into diagnostica(dolor, p_peso,vomito,estado,cantidad) values ('n','n','n','n',113);



Programa en Prolog:
% Autor: Andrés Esquivel
:-use_module(library(tabular)).
:-use_module(library(autowin)).
:-use_module(library(pce)),pce_image_directory('./Imgs').

%CONEXION A LA BD
conexion:- odbc_connect('swiprolog',_,[user('root'),password('123456'),alias(bd),open(once)]),
           odbc_prepare(bd,'SELECT cantidad FROM diagnostica where estado=? and dolor=? and vomito=? and p_peso=?',
           [atom>char(1),atom>char(1),atom>char(1),atom>char(1)],
           Handle,
           [types([integer])]),
           abolish(odbc_handle/1),
           assert(odbc_handle(Handle)).

%EJECUTAR CONSULTA
run_stmt(R,E,P1,P2,P3):- odbc_handle(Handle),
                      odbc_execute(Handle,[E,P1,P2,P3],row(R)).

%Cargar Imagenes en los frames
load_img(Ventana, Figura, Imagen, Posicion) :-
         new(Figura, figure), % crea nueva instancia Figura de clase figure
         new(Bitmap, bitmap(resource(Imagen),@on)), %instancia Bitmap, transparencia @on
         send(Bitmap, name, 1),
         send(Figura, display, Bitmap),
         send(Figura, status, 1),
         send(Ventana, display, Figura, Posicion).


%ASIGNAR IMAGENES A VENTANA PRINCIPAL Y VENTANA RESULTADOS
resource(imgTab, image, image('enfermo.jpg')).
resource(imgConEnf, image, image('noenfermo.jpg')).
resource(imgSinEnf, image, image('sienfermo.jpg')).


%VENTANA PRINCIPAL
ventana:-
        new(F, frame('Sistema Experto - Adenocarcinoma Gastrico ')),
        new(Tablero, window('Tablero',size(535,358))),
        load_img(Tablero, ImgTablero ,imgTab, point(0,0)),
        send(F, append, new(D, dialog)),
        send(D, append, new(MB, menu_bar)),
        send(MB, append, new(Evaluacion, popup(evaluacion))),
        send(MB, append, new(Autores, popup(ayuda))),
        send_list(Evaluacion, append,
        [ menu_item(diagnostico,message(@prolog,interfaz,no)),menu_item(quit,message(F, destroy))]),
        send_list(Informacion, append,

        [ menu_item('Cortijo Flores Darwin Fransua',message(@display,inform,'ESTUDIANTE DE LA  UNIVERSIDAD NACIONAL DE TRUJILLO - INTELIGENCIA ARTIFICIAL'))]),
        send_list(Informacion, append,

        [ menu_item('Esquivel Díaz Estuardo Andrés',message(@display,inform,'ESTUDIANTE DE LA UNIVERSIDAD NACIONAL DE TRUJILLO - INTELIGENCIA ARTIFICIAL'))]),
        send_list(Informacion, append,

        [ menu_item('Huaroto Rivera Luilly Anthony',message(@display,inform,'ESTUDIANTE DE LA UNIVERSIDAD NACIONAL DE TRUJILLO - INTELIGENCIA ARTIFICIAL'))]),

        send(D,append(Tablero)),
        send(F,open).



%VENTANA SECUNDARIA
interfaz(E):-E=no,
            new(Dialog,dialog('Preguntas sobre los Sintomas ')),
                      new(P1,menu('1. Tiene dolor?')),
                      send_list(P1,append,[s,n]),
                      new(P2,menu('2. Tiene vómitos?')),
                      send_list(P2,append,[s,n]),
                      new(P3,menu('3. Tiene pérdida de peso?')),
                      send_list(P3,append,[s,n]),
                      send(Dialog,append(P1)),
                      send(Dialog,append(P2)),
                      send(Dialog,append(P3)),
                      send(Dialog,append,button(ok,and(message(@prolog,
                           diagnosticoProbabilistico,
                           P1?selection,
                           P2?selection,
                           P3?selection)
                           ))),
                      send(Dialog,append,button(cancel,message(Dialog,destroy))),
                      send(Dialog,open).


%VENTANA RESULTADOS - LLAMADA POR VENTANA SINTOMAS
diagnosticoProbabilistico(P1,P2,P3):-
                                bayes(s,P1,P2,P3,Respuesta),
                                write('Respuesta'),
                                write(Respuesta),
                                %writeln(Respuesta),
                                new(Conclusion,dialog('Diagnostico Probabilistico EDA')),
                                new(Tablero, window('Tablero',size(300,200))),
                                ((Respuesta<0 .50="">load_img(Tablero, ImgEnfermo ,imgConEnf, point(0,0));load_img(Tablero, ImgEnfermo ,imgSinEnf, point(0,0))),
                                ProBayesPorcentual is Respuesta*100,
                                send(Conclusion,append(Tablero)),
                                send(Conclusion,append,label(a,'Usted tiene la EDA con una probabilidad de')),
                                send(Conclusion,append,label(a,ProBayesPorcentual)),
                                send(Conclusion,append,label(a,'%')),
                                send(Conclusion,append,button(ok,message(Conclusion,destroy))),
                                send(Conclusion,open).

%FORMULA APOSTERIORI - LLAMADA POR VENTANA RESULTADOS
bayes(E,P1,P2,P3,Probabilidad):-E=s,
                                conexion,
                                writeln(''),
                                run_stmt(R1,E,P1,P2,P3),
                                writeln(R1),
                                run_stmt(R2,n,P1,P2,P3),
                                writeln(R2),
                                Probabilidad is (R1/(R1+R2)),
                                write('Usted tiene la EDA con una probabilidad de '),
                                writeln(Probabilidad).






Imágenes usadas:






RESULTADOS:





Espero les sirva si tiene problemas con la conexion odbc - mysql les recomiendo vean esto.


jueves, 19 de mayo de 2016

Implementación del problema del granjero

Este acertijo es un forma parte de los denominados “puzzles de cruzar el río”, en los que el objetivo es mover una serie de objetos al otro lado del río siguiendo una serie de normas.
La aparición más temprana de este problema es en el manuscrito medieval Propositiones ad Acuendos Juvenes, los tres objetos son un lobo, una cabra y una col. Existen variaciones de este acertijo siendo los objetos una cabra, una oveja y un repollo; un zorro, una gallina y unas semillas; Un zorro, un ganso y una mazorca de maíz y una pantera, un cerdo y unas gachas.La lógica del acertijo sigue siendo la misma.
Este acertijo era uno de los favoritos de Lewis Carroll, y ha sido incluido en varios libros de matemática recreativa.


Planteamiento del problema:

Un granjero fue al mercado y compró un zorro una gallina y un maíz. Para volver a su casa tenía que cruzar un río. El granjero dispone de una barca para cruzar a la otra orilla, pero en la barca solo caben él y una de sus compras. Además, si el lobo se queda solo con la gallina se la come y si la gallina se queda sola con el maíz se la come. El reto del granjero era cruzar él mismo y dejar sus compras a la otra orilla del río, dejando cada compra intacta. ¿Cómo lo hizo?

Solución Teórica:

El primer paso el llevar la gallina a través del río, ya que de otro modo la gallina o el maíz serían devoradas. Cuando el granjero vuelve a la orilla original, puede elegir entre llevar al zorro o al maíz al otro lado. Si lleva al lobo, deben volver luego para llevar la al maíz, entonces el lobo se comería a la gallina. Si lleva al maíz al otro lado, necesitará volver para coger al zorro, entonces la gallina sería comida. Aquí se encuentra el dilema, se resuelve llevando el zorro (o el maíz) en la barca y trayendo de vuelta a la gallina. Ahora podemos llevar la el maíz (o el zorro), dejando la gallina y, finalmente, volver a buscar la gallina.
  • La solución se resume de la siguiente manera:
  • Deja a la gallina al otro lado
  • Vuelve
  • Deja al zorro en el otro lado
  • Regresa con la gallina
  • Deja el maíz en el otro lado
  • Vuelve
  • Deja la gallina al otro lado
De modo, que hay siete pasos: cuatro hacia la derecha y tres hacia la izquierda.

Implementación:


%accion(estado(Gra,Zorro,Gall,Maiz),estado(1,Z,1,M)).

estadoMalo(estado(0,1,1,_)).
estadoMalo(estado(0,_,1,1)).
estadoMalo(estado(1,0,0,_)).
estadoMalo(estado(1,_,0,0)).

accion(estado(0,0,G,M), estado(1,1,G,M), 'Llevar al zorro').
accion(estado(1,1,G,M), estado(0,0,G,M), 'Traer al zorro').
accion(estado(0,Z,0,M), estado(1,Z,1,M), 'Llevar la gallina').
accion(estado(1,Z,1,M), estado(0,Z,0,M), 'Traer la gallina').
accion(estado(0,Z,G,0), estado(1,Z,G,1), 'Llevar el maiz').
accion(estado(1,Z,G,1), estado(0,Z,G,0), 'Traer el maiz').
accion(estado(1,Z,G,M), estado(0,Z,G,M), 'Regresa solo').
accion(estado(0,Z,G,M), estado(1,Z,G,M), 'Ir solo').

pertenece(X,[X|_]):-!.
pertenece(X,[_|L]):-pertenece(X,L).

camino(estado(1,1,1,1),V,V).
camino(Estado,Visitado,R):-accion(Estado,NuevoEstado,A), not(estadoMalo(NuevoEstado)),
                   not(pertenece(NuevoEstado,Visitado)),
                   writeln(A),
                   camino(NuevoEstado,[NuevoEstado|Visitado],R).

solucion(L):-camino(estado(0,0,0,0),[estado(0,0,0,0)],L).

Implementación del problema de las Jarras



Es un problema que ayuda a desarrollar la destreza intelectual del usuario.
Al resolver este problema, no solo implica obtener el resultado, sino comprender la importancia de usar La
Teoría de Grafos y el algoritmo de Recorrido en Profundidad y Anchura en la solución de los problemas lógicos y algoritmos actuales, ya que nos permite hacerlo de forma ordenada y se pueden usar técnicas como el Backtracking.


Planteamiento del Problema:
  • Se tienen dos jarras, una de 4 litros de capacidad y otra de 3.
  • Ninguna de ellas tiene marcas de medición.
  • Se tiene una bomba que permite llenar las jarras de agua.
  • Averiguar cómo se puede lograr tener exactamente 2 litros de agua en la jarra de 4 litros de capacidad.
  • Enfocar este ejercicio en un área de trabajo como la agricultura, para ver su importancia y aplicación.

Análisis del problema:

Problema como el anterior es resuelto con un simple algoritmo de búsqueda; pero lo que hay que tener claro primero es cuáles son los elementos del diseño del algoritmo.
En este caso son 4 los elementos:
  • Estado inicial
  • Estado final
  • Acciones
  • Función de costo
Solución Teórica:
  • Llenar la jarra de 4 litros completamente (para ello, la jarra de 4 litros no debe estar completamente llena).
  • Llenar la jarra de 3 litros completamente (para ello, la jarra de 3 litros no debe estar completamente llena).
  • Vaciar la jarra de 4 litros (para ello, la jarra debe contener algo de líquido).
  • Vaciar la jarra de 3 litros (para ello, la jarra debe contener algo de líquido).
  • Verter el contenido de la jarra de 4 litros en la jarra de 3 litros (para ello, la jarra de 4 litros debe contener algo de líquido y la de 3 litros no estar completamente llena).
  • Verter el contenido de la jarra de 3 litros en la jarra de 4 litros (para ello, la jarra de 3 litros debe contener algo de líquido y la de 4 litros no estar completamente llena).


Implementación:


%llenar A
accion(e(X,Y),e(4,Y)):- X < 4.

%llenar B
accion(e(X,Y),e(X,3)):- Y < 3.

%vaciar A
accion(e(X,Y),e(0,Y)):- X > 0.

%vaciar B
accion(e(X,Y),e(X,0)):- Y > 0.

%vertir A en B : jarra A se queda vacia
accion(e(X,Y),e(0,Z)):- X > 0,
                        Y < 3,
                        Z is X + Y,
                        Z =< 3.
                        
%vertir A en B : jarra B se queda llena
accion(e(X,Y),e(Z,3)):- X > 0,
                        Y < 3,
                        Z is X+Y-3,
                        Z =< 4.
                        
%vertir B en A : jarra B se queda vacia
accion(e(X,Y),e(Z,0)):- Y > 0,
                        X < 4,
                        Z is X + Y,
                        Z =< 4.

%vertir B en A : jarra A se queda llena
accion(e(X,Y),e(4,Z)):- Y > 0,
                        X < 3,
                        Z is X+Y-4,
                        Z =< 3.

menu:-siguiente(e(4,0),[e(4,0)],R),
      procesa(R).

procesa([]):- !.
procesa(H|C):- procesa(C),
               writeln(H).
                        
pertenece(E,[E|_]):- !.
pertenece(E,[_|C]):- pertenece(E,C).
siguiente(e(2,_),V,V):- !.
siguiente(e(_,2),V,V):- !.
siguiente(e(X,Y),V,R):- accion(e(X,Y), e(Xs,Ys)),
                    %format('estado(~W,~W)',[Xs,Ys]),
                    not(pertenece(e(Xs,Ys), V)),
                    siguiente(e(Xs,Ys), [e(Xs,Ys)|V],R).

Métodos de Busqueda

Búsquedas por profundidad

La búsqueda en profundidad, llamada DepthFirstSearch en inglés, es un algoritmo usado para recorrer o buscar elementos en un árbol o un grafo y pertenece al grupo de las búsquedas no informadas (sin heurísticas). Su procedimiento consiste en visitar todos los nodos de forma ordenada pero no uniforme en un camino concreto, dejando caminos sin visitar en su proceso. Una vez llega al final del camino vuelve atrás hasta que encuentra una bifurcación que no ha explorado, y repite el proceso hasta acabar el árbol (esto se conoce como Backtracking). En la siguiente figura mostramos el orden de visita, siendo los números en naranja dicho orden:



En cada llamada recursiva marcaremos el nodo actual como visitado y luego verificamos si es el nodo buscado para salir de la recursión, este será nuestro caso base. De no ser el nodo requerido, se hace la llamada recursiva con todos los nodos hijos del nodo actual, pero en este caso, a diferencia del recorrido BFS, no se visitarán todos los hijos de forma consecutiva, sino que el algoritmo recorrerá en profundidad hasta llegar a un nodo extremo o nodo hoja, antes de retornar al ambiente de recursión en donde se encuentran los otros nodos hijos. El orden en que se eligen las ramas en un recorrido DFS está determinado por el tipo de recorrido de procesamiento de árbol que se haya elegido, estos pueden ser:

  • Pre-orden: Se procesa primero la raíz, luego la rama izquierda y luego las ramas siguientes hasta llegar a la que se encuentra más a la derecha.
  • Post-orden: Se procesa el árbol desde las ramas izquierdas hasta la que se encuentra más a la derecha. Finalmente se procesa el nodo raíz
  • Simétrico o In-orden: Se procesa la rama de la izquierda, luego el nodo raíz y luego la rama derecha.
Aplicado al caso del Problema de las jarras: 
En el caso del problema de las jarras, se genera el siguiente grafo de búsqueda en profundidad:


Este grafo de búsqueda por profundidad nos denota la siguiente tabla de búsqueda en profundidad:


Estados de la solución:  ((2 3) (4 1) (0 1) (1 0) (1 3) (4 0) (0 0))


Búsquedas por anchura

La búsqueda en anchura (o búsqueda en amplitud), llamada BreadthFirstSearch en inglés, es un algoritmo usado para recorrer o buscar elementos en una estructura de datos como los árboles y los grafos.Pertenece al grupo de las búsquedas no informadas(sin heurísticas). Su procedimiento consiste en ir visitando todos los nodos de un nivel antes de proceder con el siguiente nivel tal y como mostramos en la siguiente figura (los números en naranja indican el orden de exploración de los nodos):



De modo que lo primero que hará será visitar la raíz, luego los hijos de la raíz, luego los hijos de cada uno de estos hijos y así sucesivamente. 
Aplicado al caso del Problema de las jarras: 
En el caso del problema de las jarras, se genera el siguiente grafo de búsqueda en anchura:

Este grafo de búsqueda por anchura nos denota la siguiente tabla de búsqueda en anchura:



domingo, 17 de enero de 2016

IMPLEMENTACIÓN DE LOS MÉTODOS DE ORDENACIÓN EN PYTHON




Hola amigos tiempo atrás realice un post acerca delos diferentes métodos de ordenación  y su respectivo análisis de complejidad con su implementacion en java, si desean verlo pueden pasarse por la siguiente publicación:

En la presente publicación comparto con ustedes la implementación de estos métodos pero en python, un lenguaje de programación con el cual comencé a trabajar y me vi con la necesidad de implementar estos métodos 

Método de ordenamiento  Burbuja:

def ordenamientoBurbuja(lista,tam):
    for i in range(1,tam):
        for j in range(0,tam-i):
            if(lista[j] > lista[j+1]):
                k = lista[j+1]
                lista[j+1] = lista[j]
                lista[j] = k;
 
def imprimeLista(lista,tam):
    for i in range(0,tam):
        print lista[i]
 
def leeLista():
    lista=[]
    cn=int(raw_input("Cantidad de numeros a ingresar: "))
 
    for i in range(0,cn):
        lista.append(int(raw_input("Ingrese numero %d : " % i)))
    return lista
 
A=leeLista()
ordenamientoBurbuja(A,len(A))
imprimeLista(A,len(A))


Método de ordenamiento  Shell Sort:
def ordenShell(lista,tam):
    inc=1
    for inc in range(1,tam,inc*3+1):
        while inc>0:
            for i in range(inc,tam):
                j=i
                temp=lista[i]
                while j>=inc and lista[j-inc]>temp:
                    lista[j]=lista[j-inc]
                    j=j-inc
                lista[j]=temp
            inc=inc/2
 
def imprimeLista(lista,tam):
    for i in range(0,tam):
        print lista[i]
 
def leeLista():
    lista=[]
    cn=int(raw_input("Cantidad de numeros a ingresar: "))
 
    for i in range(0,cn):
        lista.append(int(raw_input("Ingrese numero %d : " % i)))
    return lista

Método de ordenamiento  QuickSort:
def quicksort(lista,izq,der):
    i=izq
    j=der
    x=lista[(izq + der)/2]
 
    while( i <= j ):
        while lista[i]< x and j< =der:
            i=i+1
        while x< lista[j] and j > izq:
            j=j-1
        if i<=j:
            aux = lista[i]; lista[i] = lista[j]; lista[j] = aux;
            i=i+1;  j=j-1;
 
        if izq < j:
        quicksort( lista, izq, j );
    if i < der:
        quicksort( lista, i, der );
 
def imprimeLista(lista,tam):
    for i in range(0,tam):
        print lista[i]
 
def leeLista():
    lista=[]
    cn=int(raw_input("Cantidad de numeros a ingresar: "))
 
    for i in range(0,cn):
        lista.append(int(raw_input("Ingrese numero %d : " % i)))
    return lista
 
A=leeLista()
quicksort(A,0,len(A)-1)
imprimeLista(A,len(A))

Método de ordenamiento  QuickSort:
def quicksort(lista,izq,der):
    i=izq
    j=der
    x=lista[(izq + der)/2]
 
    while( i <= j ):
        while lista[i]< x and j<=der:
            i=i+1
        while x< lista[j] and j>izq:
            j=j-1
        if i<=j:
            aux = lista[i]; lista[i] = lista[j]; lista[j] = aux;
            i=i+1;  j=j-1;
 
        if izq < j:
        quicksort( lista, izq, j );
    if i < der:
        quicksort( lista, i, der );
 
def imprimeLista(lista,tam):
    for i in range(0,tam):
        print lista[i]
 
def leeLista():
    lista=[]
    cn=int(raw_input("Cantidad de numeros a ingresar: "))
 
    for i in range(0,cn):
        lista.append(int(raw_input("Ingrese numero %d : " % i)))
    return lista
 
A=leeLista()
quicksort(A,0,len(A)-1)
imprimeLista(A,len(A))

Método de ordenamiento  Insercion:
def insercion(lista,tam):
    for i in range(1,tam):
        v=lista[i]
        j=i-1
        while j >= 0 and lista[j] > v:
            lista[j+1] = lista[j]
            j=j-1
        lista[j+1]=v
 
def imprimeLista(lista,tam):
    for i in range(0,tam):
        print lista[i]
 
def leeLista():
    lista=[]
    cn=int(raw_input("Cantidad de numeros a ingresar: "))
 
    for i in range(0,cn):
        lista.append(int(raw_input("Ingrese numero %d : " % i)))
    return lista
 
A=leeLista()
insercion(A,len(A))
imprimeLista(A,len(A))

Método de ordenamiento  HeapSort:
def heapsort(lista,tam):
    for k in range(tam-1,-1,-1):
        for i in range(0,k):
            item=lista[i]
            j=(i+1)/2
            while j>=0 and lista[j]< item:
                lista[i]=lista[j]
                i=j
                j=j/2
            lista[i]=item
        temp=lista[0];
    lista[0]=lista[k];
    lista[k]=temp;
 
def imprimeLista(lista,tam):
    for i in range(0,tam):
        print lista[i]
 
def leeLista():
    lista=[]
    cn=int(raw_input("Cantidad de numeros a ingresar: "))
 
    for i in range(0,cn):
        lista.append(int(raw_input("Ingrese numero %d : " % i)))
    return lista
 
A=leeLista()
heapsort(A,len(A))
imprimeLista(A,len(A))

Método de ordenamiento  MergeSort:
def merge_sort(lista): 
    n = len(lista) 
    if(n == 1): return lista 
    izquierda = merge_sort(lista[:(n/2)]) 
    derecha = merge_sort(lista[(n/2):]) 
    return merge(izquierda, derecha) 
 
def merge(izquierda, derecha): 
    resultado = [] 
    i = 0 
    j = 0 
    len_izquierda = len(izquierda) 
    len_derecha = len(derecha) 
 
    while(i < len_izquierda or j < len_derecha): 
        if(i >= len_izquierda): 
            resultado.append(derecha[j]) 
            j = j + 1 
        elif(j >= len_derecha): 
            resultado.append(izquierda[i]) 
            i = i + 1 
        elif(izquierda[i] < derecha[j]): 
            resultado.append(izquierda[i]) 
            i = i + 1 
        else: 
            resultado.append(derecha[j]) 
            j = j + 1 
    return resultado 

def imprimeLista(lista):
    for i in range(0,len(lista)):
        print (str(lista[i]))
 
def leeLista():
    lista=[]
    cn=int(input("Cantidad de numeros a ingresar: "))
    for i in range(0,cn):
        lista.append(int(input("Ingrese numero %d : " % i)))
    return lista
 
A=leeLista()
merge_sort(A)
imprimeLista(A)

jueves, 26 de noviembre de 2015

El Problema del Ruteo Vehicular con Ventanas de Tiempo




El problema del transporte con ventanas de tiempo, VRPTW (por sus siglas en inglés, Vehicle Routing Problem with Time Windows), es un modelo que se aplica a cadena de suministros y transporte escolar.
El problema se puede plantear como sigue:
Un vendedor (viajero por cierto) necesita visitar n puntos de la ciudad, sin importar el orden en que lo haga, cada uno exactamente una vez y en el menor tiempo posible. En el contexto de lo que se verá más adelante, podríamos decir que el vendedor viajero es asociable a un operador de un servicio puerta a puerta que debe atender a la demanda ubicada en la posición de cada uno de los n nodos que debe visitar.
A continuación se presenta el modelo de programación lineal entera que representa al problema:


La función objetivo presentada en (1), representa el costo total, el cual se puede interpretar como el tiempo de viaje o distancia recorrida total. Se requiere encontrar la  mínima  distancia de recorrido total utilizando el menor número de vehículos. La variable xijk, toma valor de uno cuando el vehículo k atiende la ruta que va del cliente i al cliente j. El depósito se representa como i = 0 ó i = 1 + n. Las restricciones que se deben cumplir se presentan de (2) a (11).
 Restricciones en (2), restringen la asignación de cada cliente a una sola ruta vehicular, esto es, el cliente es atendido por un sólo vehículo.
 Restricciones de (3) a (5), dan las características de  la ruta a seguir por cada vehículo k.
  • Restricciones en (3), definen el número de clientes j que son directamente alcanzables desde el depósito 0 utilizando el vehículo k, esto es, para cada vehículo k, sólo un cliente j se puede alcanzar partiendo del deposito.
  • Restricciones en (4), indica para cada unidad vehicular que, la diferencia del número de clientes i desde los cuales el cliente j es directamente alcanzable, con respecto del número de clientes i que son directamente alcanzables desde el cliente j, es cero, esto es, el número de vehículos que llegan a un cliente  es el mismo número de vehículos que sale.
  • Restricciones en (5), indica para cada unidad vehicular que, el número de clientes i desde los cuales el deposito n + 1 es directamente alcanzable, es sólo uno, esto es, cada ruta vehicular tiene un sólo cliente que conecta al depósito.
 Restricciones (6) a (8) y (9), garantizan la factibilidad de la secuencia con respecto a condiciones de tiempo y aspectos de capacidad respectivamente.
  • Restricciones en (6), indica para cada unidad vehicular y cada arco entre par de clientes, que la suma del tiempo inicial del servicio wik para el cliente i más su tiempo de servicio dado al cliente i más su tiempo de recorrido desde el cliente  i al cliente j, menos  el tiempo inicial del servicio wik es menor o igual que (1 - xijk ) = Mij, esto es, no se puede iniciar un servicio en j si el cliente i no ha sido atendido y el vehículo no ha llegado al cliente j. Aquí M es una constante muy grande.
  • Restricciones en (7), indican para cada unidad vehicular y cada cliente i, que el tiempo inicial del servicio wik debe iniciar dentro de la ventana de tiempo [aibi], donde ai es el tiempo más temprano posible que puede iniciar el servicio en el cliente i y bi  es el tiempo más tarde posible que puede iniciar el servicio en el cliente i.
  • Restricciones en (8), indican para cada unidad vehicular y en el depósito 0, que el tiempo inicial del servicio wik debe iniciar dentro de la ventana de tiempo [E, L], esto es, el vehículo k, debe tener una salida posible más temprana desde el depósito y una llegada posible más tarde al depósito.
  • Restricciones en (9),  indican que para todo vehículo k, la suma de las demandas de todos los clientes atendidos no debe exceder la capacidad del vehículo.
 Restricciones (10), son restricciones de no negatividad de las variables x.
 Restricciones (11), son restricciones que definen al modelo lineal como un modelo lineal entero binario.

 IMPLEMENTACION DE UN PROBLEMA DE RUTEO VEHICULAR CON VENTANA DE TIEMPO A LA EMPRESA “FERNADES AGRO S.A”.

PLANTEAMIENTO DEL PROBLEMA A SOLUCIONAR:
Según el ministerio de economía La Libertad estimó que este año 2015 en la región habrá una producción de más de seis millones de toneladas de caña de azúcar, siendo en gran parte de este tonelaje provenientes del valle Chicama. Si bien se sabe  en el valle Chicama  está la presencia de empresas azucareras como Cartavio, Casa Grande, Pucala que son las que mayor producción aportan, también existe la presencia de pequeños productores , agricultores que poseen algún terreno y producen caña de azúcar.
Como caso de estudio tomaremos como referente a la Empresa FERNADES AGRO S.A, una pequeña empresa ubicada en la localidad de Chiclin  y que brinda servicios de proveedor de recursos como abono, pesticidas, etc para los agricultores  dentro de su localidad.
Actualmente en la empresa se maneja dos tipos de transporte, el primero es el primario que va desde el centro de distribuciones en Lima, el cual se encarga de transportar todos los productos al establecimiento de la empresa  y el transporte secundario que es nuestro motivo de estudio, va desde su establecimiento  hasta los clientes finales que son los pequeños agricultores.
La sucursal donde nos enfocaremos es la que  está situada en la localidad de Chiclin, donde trabaja con un solo camión propio de la empresa pero en la actualidad realizan outsoutcing y cuentan con un camión de 5 toneladas  que se encargan la entrega del producto final a los clientes finales.
Para plantear este tipo de problemas necesitamos “n”  datos de la empresa y trabajaremos con 4 destinos en los cuales se realizan la distribución de los productos.

OBJETIVOS:
  •   Disminuir los tiempos de entrega de los productos por parte de la empresa hacia los consumidores.
  •   Maximizar el nivel de servicio a los clientes, optimizando la utilización de los recursos.
  •   Buscar la aplicación del objetivo general de la logística la cual consiste en maximización de nivel del servicio, minimización de costos.
  •   Elaboración de rutas de acuerdo al orden de los pedidos por parte de los consumidores.

CONSIDERACIONES:
·         En el problema que plantearemos hemos considerado las siguientes restricciones:
  •   Cada vehículo tiene una capacidad limitada (para efectos de simplificación se concibe una flota de vehículos toda con igual capacidad).
  •   Cada cliente debe ser visitado entro de una determinada ventana de tiempo.
  •   El vehículo tiene la alternativa de llegar al punto de entrega antes del inicio de la ventana de tiempo y esperar a que se inicie.

RED CON LOS DATOS DEL PROBLEMA A SOLUCIONAR:

COORDENADAS DE LOS NODOS OBTENIDAS CON GOOGLE MAPS:


POSICIONAMIENTO DE LOS NODOS OBTENIDOS EN GOOGLE  MAPS:



GRÁFICO GENERADO POR GLPK:


RESULTADOS OBTENIDOS POR GLPK:

Como vemos en la red, los vehículos tendrán que realizar un recorrido relativamente corto, optimizando de esta manera la entrega de encomiendas.


IMPLEMENTACIÓN DEL MODELO EN GLPK



# Archivo de salida
param filename, symbolic := "vrptw.svg";
set N;                  # conjunto de nodos incluido el deposito 
set K;                  # Conjunto de vehiculos
param xcoord {i in N} ;
param ycoord {j in N};
param VD:= 30;                    # Velocidad por defecto (MPH)
param f:= 90;                     # Flete em dolars
param dist{i in N, j in N:i != j} := sqrt((xcoord[i] - xcoord[j])^2 + (ycoord[i] - ycoord[j])^2); # Distancia
param c{i in N, j in N: i != j} := f * dist[i,j]/1000;  # Costo de transporte en miles de soles
param conv{i in N, j in N: i !=j} := dist[i,j]*0.0003048;   # Convertir distancia de feet em mile: mt = feet*0.0003048.
param t{i in N, j in N: i != j}:= (conv[i,j]*3600)/VD;    # Tiempo de viaje en segundos.
param d{i in N};           # demanda de los clientes i = 1, 2, 3, 4, 5, 6.
param q{k in K};           # capacidad de los vehiculos k = v1, v2, v3.
#param t{i in N, j in N};   # tiempo entre los clientes
param a{i in N};           # Limite de tiempo inferior.
param b{i in N};           # Limite de tiempo superior.
var X{i in N, j in N, k in K}, binary;   # Condiciones de acceso a una ruta, 1 - si puede hacer uso de la ruta y 0- si no puede hacer uso de la ruta.
var Y{i in N, k in K} integer ;          # vehiculo k comienza el servicio al cliente.
minimize Z: sum {i in N, j in N, k in K: i != j and (i != 0 and j != 4) and j  >  0 } c[i,j]*X[i,j,k];

s.t. R_1 {i in N: (i!= 0 and i != 4)}: sum{j in N, k in K: i !=j }X[i,j,k] = 1; # Un Cliente puede ser visitado unicamente por un vehiculo

s.t. R_2 {k in K}: sum{i in N, j in N: (i != 0 and i != 4 and i != j) }d[i]*X[i,j,k]   < = q[k];  # Demanda no excede la capacidad del vehiculo

s.t. R_3 {k in K}: sum {i in N, j in N: i == 0 and i !=j } X[i,j,k]  = 1;                        # Cada vehiculo deja el deposito

s.t. R_4 {h in N, k in K: (h != 0 and h != 4)}: sum{i in N: i != h} X[i,h,k] - sum{j in N: h != j}X[h,j,k] = 0; # Conservacion de flujo

s.t. R_5 {k in K}: sum{i in N, j in N: j == 4 and i!= j and i  > =0 }X[i,j,k] = 1;

s.t. R_6{i in N, j in N, k in K: i != 0 and i != 4 and i != j }: Y[i,k]  + t[i,j]  - 10000*(1 - X[i,j,k])  < = Y[j,k]; # Llegar al cliente j.

s.t. R_7{i in N, k in K: i != 0 and i != 4}: Y[i,k]  > = a[i];   # ventana de tiempo

s.t. R_8{i in N, k in K: i != 0 and i != 4 }: Y[i,k]  < = b[i];  # ventana de tiempo


solve;

printf " < ?xml version=""1.0"" standalone=""no""? > \n"  >  filename;
printf " < !DOCTYPE svg PUBLIC ""-//W3C//DTD SVG 1.1//EN"" \n"  >  >  filename;
printf """http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"" > \n"  >  >  filename;
printf " < svg width=""1000\%"" height=""1000\%"" version=""1.0"" \n"  >  >  filename;
printf "xmlns=""http://www.w3.org/2000/svg"" > \n"  >  >  filename;


for{i in N}
{
   printf " < text x=""%f"" y=""%f"" fill=""black"" > ""%s"" < /text > ",xcoord[i]*3, ycoord[i]*3,i  >  > filename;
   printf " < circle cx=""%f"" cy=""%f"" r=""%f"" / > \n",  xcoord[i]*3, ycoord[i]*3 ,3.5  >  > filename;
}

# draw solid black lines for integer connections
for {i in N,j in N, k in K : i != j and X[i,j,k] == 1}
  printf " < line x1=""%f"" y1=""%f"" x2=""%f"" y2=""%f""" &
         " style=""stroke:blue;stroke-width:1""/ > \n",
         xcoord[i] * 3, ycoord[i] * 3, xcoord[j] * 3, ycoord[j] * 3  >  >  filename;

printf " < /svg > \n"  >  >  filename;

printf "\n" ;
printf "  Costo y asignacion de vehiculos:  %s\n",
sum {i in N, j in N, k in K: i != j and (i != 0 and j != 4) and j  > 0} c[i,j]*X[i,j,k];
printf("      Arco        Vehiculo   \n");
printf "\n" ;
printf {i in N, j in N, k in K: X[i,j,k] } "      %1s  %2s   %10s   \n", i, j, k;

data;

set N := 0 1 2 3 4 ;
set K := 'v1';

param:             xcoord  ycoord :=
           0        10       15
           1        82       76
           2        96       44
           3        50       5
           4        49       8;
           


param d :=
         0     0
         1    10
         2    30
         3    10
         4    10;
         


param q :=
       'v1'   200;
      


param  a :=
  0   0400
  1   0700
  2   0000
  3   0000
  4   0700;
       



param  b :=
  0   1500
  1   2400
  2   2400
  3   0700
  4   2400;
       
end;