jueves, 12 de julio de 2012

Análisis de complejidad asintótica de heurísticos

Complejidad es la medida del uso de algún recurso por parte de un algoritmo, estos recursos pueden ser requerimientos de almacenamiento, memoria o tiempo. 
Por lo general, la cantidad de tiempo que un algoritmo toma es el recurso más encontrado.
El análisis asintótico es la determinación de cantidad de recursos usados por un algoritmo.

En esta entrada graficamos
Búsqueda Tabú 
Búsqueda Local
Recocido Simulado
Algoritmo Genético
HiperHeuristicos
Serán dos graficas por cada Heurística con una densidad de 0.6
Significados de las abreviaciones
  • BL= Local
  • BT=Búsqueda Tabú
  • RS=Recocido Simulado
  • AG=Algoritmo Genético
  • HH=Hiperheuristico 
Tomamos en Cuenta los Criterios mencionados a continuación:
Tiempo será medido en segundos
Memoria será medida en bytes
Numero de Vértices

Búsqueda Local 



Búsqueda Tabú



Recocido Simulado





Algoritmo Genético



HiperHeurísticos


Bibliografia:



karenalduncin  wtf Dx

Visualización de evaluación de heurísticos

La evaluación heurística es un análisis de experto en el cual se hace una inspección minuciosa a interfaces o sistemas con el fin de determinar si cada uno de sus elementos se adhieren o no a los principios de usabilidad, diseño o arquitectura de informaición comúnmente aceptados en sus respectivas disciplinas. Esta entrada trata de evaluar el tiempo, la memoria y objetivo de nuestro programa 

gnuplot> set xrange [0:80]
gnuplot> set size 1.2, 1
gnuplot> set xrange [0:100]>
gnuplot> set ytics 10,2
gnuplot> set Title "Tiempo"


gnuplot> set title "Tiempo"
gnuplot> set origin 0,1
gnuplot> set yrange [0:5]
gnuplot> set ytics 3,10
gnuplot> set title "Memoria"
gnuplot> set origin 1.2, 1
gnuplot> set yrange [0:5]
gnuplot> set ytics 1,1
gnuplot> set title "Objetivo"
gnuplot> set origin 2.4,1
gnuplot> set yrange [0:5]



10 15 1 22 36
10 15 1 23 56
11 23 2 28 57
12 24 2 44 76










39 13 12 2 22
39 14 13 3 45
42 14 28 3 45
87 19 34 3 59




43 3 59 2 32
31 3 45 2 24
28 3 45 1 10
21 2 22 1 13










       





miércoles, 11 de julio de 2012

Análisis estadístico de desempeño

En éste análisis obtendremos el tiempo de ejecución, la cantidad total de memoria utilizada y calidad de la solución generada para cada una de las heurísticas ya conocidas y lo meteremos a un archivo para su posterior uso.


Código:
 ArrayList <Integer> usos = new ArrayList<Integer>();
 Hashtable <String, Double> heuristica = new Hashtable <String, Double>();
 Hashtable <String, Integer> contador = new Hashtable <String, Integer>();
 String opciones[] = {"local", "tabu", "recocido", "genetico"};
 Runtime rt = Runtime.getRuntime(); 
 BufferedWriter out = new BufferedWriter(new FileWriter("instancias.txt"));
 
 for(int i = 0; i < opciones.length ; i++){ 
  heuristica.put(opciones[i], 1.0);
 }


 ArrayList<Integer> actual = Arista.inicial(grafo);


 while(reinicio <= re){
 
    int indice = ruletaheur(heuristica, opciones);
  
  if(contador.containsKey(opciones[indice])){
   int valor = contador.get(opciones[indice]);
   valor += 1;
   contador.put(opciones[indice], valor);
  }else{
   contador.put(opciones[indice], 1);  
  }
  
 System.out.print("Usando "+opciones[indice] +" en reinicio " +re +"\n"); 
 long tiempoInicio = System.currentTimeMillis();
 long memoriaInicio = rt.freeMemory(); 
 
 switch(indice) {
  case 0:
      break;
  case 1: 
      sol = tabu(actual, tabu);
      if(sol <= actual){
       actual = sol;
       double puntos = heuristica.get(opciones[indice]);
       puntos *= premio;
       heuristica.put(opciones[indice], puntos);
      }
      break;
  case 3: 
      sol = recocido(actual);
      if(sol <= actual){
       actual = sol;
       double puntos = heuristica.get(opciones[indice]);
       puntos *= premio;
       heuristica.put(opciones[indice], puntos);
      }
      break;
  case 4: 
      sol = nacimiento(pob, n, grafo);
      if(sol <= actual){
       actual = sol;
       double puntos = heuristica.get(opciones[indice]);
       puntos *= premio;
       heuristica.put(opciones[indice], puntos);
      }
      break;
  }  

 long tiempoFinal = System.currentTimeMillis();
    long memoriaFinal = rt.freeMemory();

   out.write(reinicio);
   out.write("  ");
   out.write(String.valueOf(tiempoFinal-tiempoInicio));
   out.write("  ");
   out.write(String.valueOf(memoriaInicio-memoriaFinal));
   out.write("  ");
   out.write(String.valueOf(sol));
   out.newLine(); 
 reinicio++;   
 }   

martes, 10 de julio de 2012

Hiperheurísticos

La hiperheurística consiste básicamente en hacer uso de un conjunto de varias heurísticas que ya conocemos para ir generando diversas soluciones que se irán evaluando y así poder determinar cuál heurística es la que nos conviene para resolver el problema propuesto. La idea es que al principio las heurísticas a usar se elijan aleatoriamente y después con un sistema de premios y castigos, ir dando prioridad a las heurísticas que mejores resultados obtengan en el menor tiempo.




Código:

    public static int ruletaheur (Hashtable <String, Double> heuristica, String opciones[]){
     
     double total = 0.0;
     
     for(int i = 0; i < heuristica.size(); i++){
      double opcion = heuristica.get(opciones[i]);
      total += opcion;
     }
     
     double corte = Arista.r.nextInt((int)total);
     total = 0.0;
     for(int i = 0; i < heuristica.size(); i++){
      double opcion = heuristica.get(opciones[i]);
      total += opcion;
      if(total >= corte){
       return i;
      }
     }
    return 0; 
    } 






 ArrayList <Integer> usos = new ArrayList<Integer>();
 Hashtable <String, Double> heuristica = new Hashtable <String, Double>();
 Hashtable <String, Integer> contador = new Hashtable <String, Integer>();
 String opciones[] = {"local", "tabu", "recocido", "genetico"};

 
 for(int i = 0; i < opciones.length ; i++){ 
  heuristica.put(opciones[i], 1.0);
 }


 ArrayList<Integer> actual = Arista.inicial(grafo);


 while(reinicio <= re){
 
    int indice = ruletaheur(heuristica, opciones);
  
  if(contador.containsKey(opciones[indice])){
   int valor = contador.get(opciones[indice]);
   valor += 1;
   contador.put(opciones[indice], valor);
  }else{
   contador.put(opciones[indice], 1);  
  }
  
 System.out.print("Usando "+opciones[indice] +" en reinicio " +re +"\n"); 
  
 
 switch(indice) {
  case 0:
      break;
  case 1: 
      sol = tabu(actual, tabu);
      if(sol <= actual){
       actual = sol;
       double puntos = heuristica.get(opciones[indice]);
       puntos *= premio;
       heuristica.put(opciones[indice], puntos);
      }
      break;
  case 3: 
      sol = recocido(actual);
      if(sol <= actual){
       actual = sol;
       double puntos = heuristica.get(opciones[indice]);
       puntos *= premio;
       heuristica.put(opciones[indice], puntos);
      }
      break;
  case 4: 
      sol = nacimiento(pob, n, grafo);
      if(sol <= actual){
       actual = sol;
       double puntos = heuristica.get(opciones[indice]);
       puntos *= premio;
       heuristica.put(opciones[indice], puntos);
      }
      break;
  }  
  
  
 reinicio++;   
 }   
  
 for(int i = 0; i < opciones.length ; i++){ 
  System.out.print("Heuristica "+opciones[i] +" fue usada " +contador.get(opciones[i]) +" veces; puntuacion final: " +heuristica.get(opciones[i]) +"\n");
 }  





viernes, 6 de julio de 2012

Metaheurística Genética Básica

La Metaheurística Genética Básica Genera una Población de soluciones iniciales después así 
poder elegir al azar una de estas soluciones y mutarlas o cruzarlas y generar mas nuevas  soluciones para despues eliminar y solo conservar las generaciones que contengan las mejores soluciones este es el avance de la clase.

//
genera una poblacion inicial

    public static ArrayList<ArrayList<Integer>> poblacion(ArrayList <Arista> grafo,int tam)//verif
    {
 ArrayList<ArrayList<Integer>> lista= new ArrayList<ArrayList<Integer>>();
 while(lista.size()<=tam)
     {
  lista.add(Arista.inicial(grafo));
     }
 //System.out.println("Poblacion @_@");
 // Arista.imprime(lista);
 return lista;
    }
    //cromosoma
    public static ArrayList<String> cromosoma(ArrayList<Integer> seleccion, int cantidad)
    //cantidad total de vertices 
    {
 ArrayList<String> ref = new ArrayList<String>();
 for(int i=0;i<cantidad;i++)
     {
  if(seleccion.contains(i))
     {
         ref.add("1");
     }
     else
         ref.add("0");
     }
 //Arista.imprime(ref);
        return ref;
    }

    public static ArrayList<Integer> cubierta (ArrayList<String> cromosoma)
    {
 ArrayList<Integer> selection= new ArrayList<Integer>();
 int pos =0;
  for (int i=0;i<cromosoma.size();i++)
     {
  if((cromosoma.get(i)).equals("1"))
      selection.add(pos);
  pos+=1;
     }
 //System.out.println("cubierta");
 //Arista.imprime(selection);
 return selection;
    }

    public static void mutacion(ArrayList<ArrayList<Integer>>poblacion,int verticestotales,ArrayList<Arista> g)
    {
 int individuo = Arista.r.nextInt(poblacion.size());
 ArrayList<Integer> id = poblacion.get(individuo);
 //System.out.println("id");
 //Arista.imprime(id);
 ArrayList<String> cr =cromosoma(id,verticestotales);
 int ubic= Arista.r.nextInt(verticestotales);
 if (cr.get(ubic)== "0")//si el individuo seleccionado es igual a 0
     {
  cr.set(ubic,"1"); 
     }
 else
     {
  cr.set(ubic,"0");
     }
 //System.out.println("cadenita");
 //Arista.imprime(cr);
 ArrayList <Integer> mutante = Arista.cubierta(cr);
 // System.out.println("mutante");
 //Arista.imprime(mutante);
 int objetivo = Arista.objetivo(mutante);
 boolean fact = Arista.factible(mutante,g);
 if(fact==true )
     poblacion.add(mutante);
 return;
    }
    
    public static void nacimiento(ArrayList<ArrayList<Integer>>poblacion,int n,ArrayList<Arista> g)
    {
 int i=0;
 ArrayList<String> papa = cromosoma(poblacion.get(Arista.r.nextInt(poblacion.size())),n);
 ArrayList<String> mama = cromosoma(poblacion.get(Arista.r.nextInt(poblacion.size())),n);
 int pos = Arista.r.nextInt(n);
 //mama
 ArrayList<String> hija=null;
 ArrayList<String> hijo=null;
 Iterator<String> pa = papa.iterator();//recorre 
 Iterator<String> ma = mama.iterator();
 while (pa.hasNext() && ma.hasNext()) {
     if(i<pos)
  {
      hija.add(pa.next());
      hijo.add(ma.next());
     i++;
  }
     else
  {
      hija.add(ma.next());
      hijo.add(pa.next());
      i++;
  }
 }
 System.out.println("mama");
 Arista.imprime(mama);
 System.out.println("papa");
 Arista.imprime(papa);
 System.out.println("hija");
 Arista.imprime(hija);
 System.out.println("hijo");
 Arista.imprime(hijo);
 poblacion.add(hija);
 poblacion.add(hijo);   
 return ;
 }

jueves, 5 de julio de 2012

Busqueda Recocido Simulado

El Enfriamiento o Recocido Simulado es un algoritmo de búsqueda por entornos con un criterio probabilístico de aceptación de soluciones basado en enfriamiento (Termodinámica).

„ Un modo de evitar que la búsqueda local finalice en óptimos locales, hecho que suele ocurrir con los algoritmos tradicionales de búsqueda local, es permitir que algunos movimientos sean hacia soluciones peores„ Pero si la búsqueda está avanzando realmente hacia una buena solución,
estos movimientos “de escape de óptimos locales” deben realizarse de un modo controlado,esto se realiza controlando la frecuencia de los movimientos de escape mediante una función de
probabilidad que hará disminuir la probabilidad de estos movimientos hacia soluciones peores conforme avanza la búsqueda (y por tanto estamos más cerca, previsiblemente, del óptimo local)
„ Así, se aplica la filosofía habitual de búsqueda de diversificar al principio e intensificar al final.
Hace uso de una variable llamada Temperatura, T, cuyo valor determina en qué medida pueden ser aceptadas soluciones vecinas peores que la actual?? La variable Temperatura se inicializa a un valor alto, denominado Temperatura inicial, T0, y se va reduciendo cada iteración mediante un mecanismo de enfriamiento de la temperatura, α(·), hasta alcanzar una Temperatura final, Tf

#Vertices = 12 Densidad = .4
Se generaron 29 aristas.
#instancia
(0, 1)
(0, 3)
(0, 9)
(0, 11)
(1, 8)
(1, 9)
(1, 10)
(1, 11)
(2, 3)
(2, 5)
(2, 6)
(2, 10)
(3, 4)
(3, 5)
(3, 6)
(3, 7)
(4, 5)
(4, 6)
(4, 7)
(4, 8)
(4, 11)
(5, 10)
(5, 11)
(6, 7)
(6, 8)
(6, 9)
(6, 10)
(6, 11)
(8, 9)
Cota inferior: 5.
Cota superior: 10.


0 0 8 factible
0 1 8 factible
0 2 8 factible
0 3 8 factible
0 4 8 factible
1 0 10 factible
RS 9 factible
1 1 9 factible
1 2 9 factible
1 3 9 factible
1 4 9 factible
2 0 9 factible
2 1 9 factible
RS 8 factible
2 2 8 factible
2 3 8 factible
2 4 8 factible
3 0 9 factible
3 1 9 factible
3 2 9 factible
3 3 9 factible
3 4 9 factible
4 0 11 factible
4 1 10 factible
4 2 10 factible
4 3 10 factible
RS 9 factible
4 4 9 factible
5 0 8 factible
5 1 8 factible
5 2 8 factible
5 3 8 factible
5 4 8 factible
6 0 10 factible
6 1 10 factible
RS 9 factible
6 2 9 factible
6 3 9 factible
6 4 9 factible


Se realizaron cambios a la función búsqueda...
public static ArrayList<Integer> busqueda(ArrayList<Arista> grafo, int n,int it,int re,int temperact, double enfriamiento) {
        //ArrayList<ArrayList<Integer>> lista = new ArrayList<ArrayList<Integer>>();
 ArrayList<Integer> mejorSol = null;
 // int intentos =0;
 //boolean TAB;
 //define la mejor solucion como nula para que cualquiera pueda mejorarla
 int mejorObj = n;//tamaño de la cubierta inicial seria el total de nodos en el grafo idem
 ArrayList<Integer> lista = new ArrayList<Integer>();
 
 for (int reinicio = 0; reinicio < re; reinicio++) {//pasos de reinicio
     ArrayList<Integer> solucion = Arista.inicial(grafo);//solucion inicial
     //Arista.imprime(solucion);
     int obj = Arista.objetivo(solucion);//objetivo de solucion
     //temperact=1000;
     for (int iter = 0; iter < it; iter++) {//iteraciones de comparar
  boolean fact = Arista.factible(solucion, grafo);//la solucion es factible
  ArrayList<Integer> otrasolucion = modificacion(solucion, n, fact); //modifica la solucion inicial a otra solucion
  boolean otraFact = Arista.factible(otrasolucion, grafo);//verifica que sea factible
  int otraObj = Arista.objetivo(otrasolucion);//el objetivo de esta
  int temp= mejorObj - obj;
  if (otraFact && otraObj <= obj) {//si la otra es factible y el objetivo es menor igual 
      solucion = otrasolucion;//ahora cambian de papel
      obj = otraObj;
      fact = otraFact;
      if(Arista.r.nextDouble() <= Math.exp(temp))//
   {
       temperact*= enfriamiento;
       lista.add(otraObj);
       System.out.println("RS "+ otraObj+ (fact ? "  factible" : "  no factible"));
   }
      
      if (obj < mejorObj) {//si es mejor que el mejor objetivo
   mejorObj = obj;
   mejorSol = new ArrayList<Integer>();//la agrega como mejor solucion
   Iterator<Integer> ve = solucion.iterator();
   while (ve.hasNext()) {
       mejorSol.add(ve.next());
   }
      }
  } 
  lista.add(mejorObj);
  System.out.println(reinicio + " " +iter + " " + obj + " " + (fact ? "factible" : "no factible")) ;
     }
 }
 //Arista.imprime(lista);
 return mejorSol;
    }


martes, 3 de julio de 2012

Búsqueda Tabú

El algoritmo consiste en utilizar Búsqueda Local pero con una solución inicial brindada con un factor de azar. La solución que brinda se guarda para futuras comparaciones y será actualizado en aquellos casos donde la nueva solución sea mejor que la anterior.

El motivo por el cual se parte de una solución inicial al azar es porque, al ser GRASP un algoritmo que solamente termina cuando llega a su límite de iteraciones máximas o durante unas iteraciones predeterminadas no hubo cambios. Si la solución fuese la cota inferior, siempre partiría de la misma, y siempre llegaría a lo mismo, terminando el algoritmo en los pasos dichos por la cantidad de iteraciones sin cambios.

-while
-Genera Solución inicial
-Aplica Busqueda Local
-if la solucion actual es mejor solucion
   mejorSol= solActual
}}
return  mejorSol;



En el peor caso, el algoritmo deberá  iterar hasta alcanzar la cantidad máxima de iteraciones (ya que se supone que es mucho mayor a la cantidad de iteraciones que deben pasar sin cambios para parar). Dado que en cada iteración se ejecutan SolucionInicial y la BusquedaLocal, la complejidad sería
                        O(im ∗ (n² + n⁵ m)) = O(im ∗ n⁵ m)
aunque, por supuesto, no se espera que llegue nunca a ejecutar casos de ese estilo.

En cada etapa construir una lista de candidatos con movimientos admisibles Ordenados con respecto a su beneficio.
Restringir la lista de forma que contenga buenos movimiento aunque no necesariamente óptimo „ Restringir por cardinalidad (los Objetivos mejores)

Idea:produce una diversidad de buenas soluciones, se espera que al menos una de ellas esté en un entorno de la solución óptima.
Se generaron 15 aristas.
Cota inferior: 4.
Cota superior: 7.
0 0 5 factible
0 1 5 factible
0 2 5 factible
0 3 5 factible
0 4 5 factible
1 0 7 factible
1 1 7 factible
1 2 7 factible
1 3 7 factible
1 4 7 factible
2 0 7 factible
2 1 7 factible
2 2 7 factible
2 3 6 factible
2 4 6 factible
3 0 7 factible
3 1 6 factible
3 2 6 factible
3 3 6 factible
3 4 6 factible
4 0 7 factible
4 1 7 factible
4 2 7 factible
4 3 7 factible
4 4 7 factible
5 0 6 factible
5 1 6 factible
5 2 6 factible
5 3 6 factible
5 4 6 factible
6 0 7 factible
6 1 7 factible
6 2 7 factible
6 3 7 factible
6 4 7 factible



public static boolean tabu (ArrayList<ArrayList<Integer>>cola, ArrayList<Integer> solucion, int iter)
    {
 cola = null;
 while(iter>0)
     { 
  if(cola.contains(solucion))
      {
   //cont++;modifica();
   return false;
      }
  else 
      {
   cola.add(solucion);
   if (cola.size()>=iter)
       {
    cola.remove(cola.get(0));
       }
      }
     }
 return true;
    }
    //busqueda**
    public static ArrayList<Integer> busqueda(ArrayList<Arista> grafo, int n,int it,int re) {
 ArrayList<ArrayList<Integer>> listatabu = new ArrayList<ArrayList<Integer>>();
 ArrayList<Integer> mejorSol = null;
 int intentos =0;
 boolean TAB;
 //define la mejor solucion como nula para que cualquiera pueda mejorarla
 int mejorObj = n;//tamaño de la cubierta inicial seria el total de nodos en el grafo idem
 ArrayList<Integer> lista = new ArrayList<Integer>();
 
 for (int reinicio = 0; reinicio < re; reinicio++) {//pasos de reinicio
     ArrayList<Integer> solucion = Arista.inicial(grafo);//solucion inicial
     //Arista.imprime(solucion);
     int obj = Arista.objetivo(solucion);//objetivo de solucion
     
     for (int iter = 0; iter < it; iter++) {//iteraciones de comparar
  boolean fact = Arista.factible(solucion, grafo);//la solucion es factible
  ArrayList<Integer> otrasolucion = modificacion(solucion, n, fact); //modifica la solucion inicial a otra solucion
  boolean otraFact = Arista.factible(otrasolucion, grafo);//verifica que sea factible
  int otraObj = Arista.objetivo(otrasolucion);//el objetivo de esta
  if (otraFact && otraObj <= obj) {//si la otra es factible y el objetivo es menor igual 
      solucion = otrasolucion;//ahora cambian de papel
      obj = otraObj;
      fact = otraFact;
      if (obj < mejorObj) {//si es mejor que el mejor objetivo
   mejorObj = obj;
   mejorSol = new ArrayList<Integer>();//la agrega como mejor solucion
   Iterator<Integer> ve = solucion.iterator();
   while (ve.hasNext()) {
       mejorSol.add(ve.next());
   }
      }
  } 
  System.out.println(reinicio + " " +iter + " " + obj + " " + (fact ? "factible" : "no factible")) ;
     }
 }
 // return mejorSol;//regresa la mejor solucion 
 //incluir busqueda tabú

 while(intentos>0)
     {
  TAB=false;
  int Obj=Arista.objetivo(mejorSol);
  boolean fact=Arista.factible(mejorSol,grafo);
  ArrayList<Integer> Actual = Arista.modificacion(mejorSol,n,fact);
  fact=Arista.factible(Actual,grafo);
  int objetivo=Arista.objetivo(Actual);
  
  if(tabu(listatabu,Actual,10)==true)//lista!
      {
   if(fact==true && Obj<=objetivo)
       {
    TAB=true;
    mejorSol = Actual;
    Obj = objetivo;
    if(objetivo<Obj)
       {
    System.out.println("MejorSolucion "+mejorSol+"Cobertura"+Obj+".");
    Arista.imprime(listatabu);//
       }
    if(TAB ==false)
        {
     intentos --;
        }  
    else
        System.out.println("reintenta ->"+"#intentos:"+intentos);      
       }
      }
     }
 return mejorSol;
    }


lunes, 2 de julio de 2012

Búsqueda Local

Los algoritmos de búsqueda local se caracterizan por definir, dada una posible
solución del problema, soluciones vecinas. Dos soluciones se consideran vecinas si
ellas son parecidas bajo algún criterio. Definida la función de vecindad, el algoritmo lo
que hace es generar una solución inicial y proseguir a enumerar sus vecinos. Después bajo algún criterio se selecciona una mejor solución de acuerdo a la función objetivo.

La función objetivo esta  definida como un valor  (en este caso el numero de vértices que se utilizaron para la cubierta modificada). Luego reinicia el procedimiento pero esta vez tomando como solucion inicial a la elegida anteriormente como mejor vecina. El algoritmo  finaliza cuando no existe una mejor solución que la actual.
Notar que la heurística (tal y como por definición de heurística debería de ser) no
es exacta, es decir que no brinda (necesariamente) la mejor solución al problema.

Como solución inicial se eligió una bastante sencilla. Consistió en recorrer todos los conjuntos de nodos y verificar si en la solución a devolver no existía ya alguno de sus aristas . De no ser así se agregaba uno al azar.

-Se genera solución inicial
-mientras no encuentre un menor resultado
    s= solución actual       
-el actual sera el mejor
-regresa el mejor


BusquedaLocal
El algoritmo lo primero que realiza es generar la solución inicial, lo cual le cuesta O(nm). Luego ejecuta modifica y búsqueda hasta encontrar una mejor solución. Dado que el bucle se ejecuta si hay una mejora en la soluci ́n, y que  ́sta no puede tener mas de n nodos, el caso en donde más veces iterará será cuando la otra solución arroje un resultado de longitud n y en cada iteración se disminuya la respuesta en uno, hasta alcanzar el mínimo en un conjunto con un solo nodo. En éste caso se harían n iteraciones, por lo que la complejidad sería

O(nm + n(n⁴ m)) = O(n⁵ m).

# Instancia generada para 5 vértices con densidad .5 

Cota inferior: 3.
Cota superior: 2.
 
0 0 2 factible
0 1 2 factible
0 2 2 factible
0 3 2 factible
0 4 2 factible
1 0 2 factible
1 1 2 factible
1 2 2 factible
1 3 2 factible
1 4 2 factible
2 0 2 factible
2 1 2 factible
2 2 2 factible
2 3 2 factible
2 4 2 factible
3 0 3 factible
3 1 3 factible
3 2 3 factible
3 3 3 factible
3 4 3 factible
4 0 3 factible
4 1 3 factible
4 2 3 factible
4 3 3 factible
4 4 3 factible





/**
       Crea el conjunto de solucion inicial 
       lo mismo que el procedimiento de la cota inferior pero en lugar de ordenarlo 
     */
    public static ArrayList<integer> inicial(ArrayList<arista> grafo) { //lista de solucion inicial 

 ArrayList<integer> cubierta = new ArrayList<integer>();//lista de la cubierta (conjunto seleccionado como solucion inicial)
 ArrayList<arista> copia = new ArrayList<arista>();//lista de aristas copia de la cubierta 
 //de nuevo recorre el grafo 
 Iterator<arista> it = grafo.iterator();
 while (it.hasNext()) {
     copia.add(it.next());//y lo agrega a la copia
 }
 //si el conjunto es mayor a 0 
 while (copia.size() > 0) {
     int largo = copia.size();//se toma el largo del arreglo de aristas 
     //System.out.println("Faltan " + largo + " aristas por cubrir.");//el largo de las aristas 
     /**SELECCIONA*/
     //selecciona un vertice al azar y lo toma en el conjunto seleccion 
     int seleccion = Arista.r.nextInt(largo);
     //System.out.println(seleccion);
     //de acuerdo a la posicion del elemento seleccionado verifica el arista
     Arista a = copia.get(seleccion);
     //cualquier vertice tenga este arista podra formar parte del conjunto de seleccion
     if (Arista.r.nextBoolean()) {
  seleccion = a.desde;
     } else {
  seleccion = a.hasta;
     }
     //crea la cubierta con los elementos seleccionados
     cubierta.add(new Integer(seleccion));
     it = grafo.iterator();
     //lista de aristas eliminados
     ArrayList<arista> eliminados = new ArrayList<arista>();
     //agrega los eliminados tanto los vertices hasta y desde  a la lista 
     while (it.hasNext()) {
  a = it.next();
  //si los aristas forman parte de la seleccion los agrega a la lista eliminados 
  if (a.desde == seleccion || a.hasta == seleccion) {
      eliminados.add(a);
  }
     }
     copia.removeAll(eliminados); //de la copia quita los eliminados
 }

 return cubierta;//regresa la cubierta seleccionada como solucion inicial 
}
public static boolean factible(ArrayList<integer> solucion, ArrayList<arista> grafo) {
 Iterator<arista> it = grafo.iterator();//recorre la lista de aristas del grafo
 while (it.hasNext()) {
     Arista a = it.next(); //
     if (!(solucion.contains(new Integer(a.hasta)) || solucion.contains(new Integer(a.desde)))) {
  //si la solucion no contiene(cubre) todas las aristas regresa un false no es factible 
  return false;
     }
 }
 return true; //y si si pues si :D
    }
    /**Recibe una solucion inicial 
       Regresa el tamaño de la modificacion 
     */
    public static ArrayList<integer> modificacion(ArrayList<integer> solucion, int n, boolean fact)//recibe solucion inicial
    {
 ArrayList<integer> nueva = new ArrayList<integer>();//nueva es la copia de una solucion inicial
 int k = solucion.size();// tamaño de esta
 int brinca = (fact || k == n) ? Arista.r.nextInt(k) : -1;
        //si es factible o es igual al total de vertices quita un elemento de forma aleatoria 
 
 for (int i = 0; i < k; i++) {
     if (i != brinca) {
  nueva.add(solucion.get(i));//agrega un nuevo vertice a la solucion
     }
 }
 if (!fact && k < n) {//si no es factible y el tamaño de la solucion inicial es menor 
     while (true) {
  Integer agrega = new Integer(Arista.r.nextInt(n));//agrega
  if (nueva.indexOf(agrega) < 0) {
      nueva.add(agrega);
      break;
  }
     }
 }

 return nueva;//regresa la nueva
    }
    //busqueda
    public static ArrayList<Integer> busqueda(ArrayList<arista> grafo, int n) {
 ArrayList<integer> mejorSol = null;
        //define la mejor solucion como nula para que cualquiera pueda superarla
 int mejorObj = n;//tamaño de la cubierta inicial seria el total de nodos en el grafo idem

 for (int reinicio = 0; reinicio < 5; reinicio++) {//pasos de reinicio
     ArrayList<Integer> solucion = Arista.inicial(grafo);//solucion inicial
     //Arista.imprime(solucion);
     int obj = Arista.objetivo(solucion);//objetivo de la solucion

     for (int iter = 0; iter < 5; iter++) {//iteraciones de comparar
  boolean fact = Arista.factible(solucion, grafo);//la solucion es factible
  ArrayList<Integer> otrasolucion = modificacion(solucion, n, fact);
                //modifica la solucion inicial en otrasolucion
  boolean otraFact = Arista.factible(otrasolucion, grafo);
                //verifica que sea factible
  int otraObj = Arista.objetivo(otrasolucion);//define su tamanio
  if (otraFact && otraObj <= obj) {//si es mejor que la anterior
      solucion = otrasolucion;//se toma esa solucion
      obj = otraObj;//ese objetivo
      fact = otraFact;//la factibilidad
      if (obj < mejorObj) {//y se convierte en la mejor
   mejorObj = obj;//:3
   mejorSol = new ArrayList<Integer>();
   Iterator<integer> it = solucion.iterator();
   while (it.hasNext()) {
       mejorSol.add(it.next());
   }
      }
  } 
  System.out.println(reinicio + " " +iter + " " + obj + " " + (fact ? "factible" : "no factible")) ;
     }
 }
 return mejorSol;//devuelve la mejor solucion 
    }



Referencias
Informe Algoritmos 2007

viernes, 29 de junio de 2012

Evaluacion de función objetivo, factibilidad de la solución y soluciones iniciales

Evaluación Función Objetivo
El Objetivo es cubrir la mayor cantidad de aristas con la menor cantidad de nodos  (vertices).
Área Factible  se  define como los vértices que cubren la cantidad de aristas totales en el grafo. En el peor de los casos serian todos los vértices, pero se necesita una solución inicial  que cumpla con la condición que sean la menor cantidad de vértices para esto compararemos a la par el vértice que contiene la mayor cantidad de vecinos  para poder cubrir así la mayor área, ya teniendo ese vértice eliminaremos de una lista las aristas que están cubiertas por ese vértice y volveremos a verificar el siguiente vértice que tiene la mayor cantidad de vecinos (aristas) y lo pondremos en nuestra lista de vértices que constituyen la solución inicial y seguiremos eliminando de la lista de aristas las que ya están cubiertas y si en esta lista ya no existen aristas disponibles termina la función de evaluar el área factible.



Generar una Solución Inicial constituye el hecho de que sea una solución dentro del área factible para poder partir de ahí y poder mejorarla, esto se definiría como la cantidad de vértices utilizados representados de alguna forma por ejemplo vértice A vértice C y vértice F cubren todos los aristas por ello es una solución inicial más no la óptima.

for(i=1;i<=vertices;i++){

      for(j=1;j<=maxar;j++){


 g[i][j] = conectado(densidad);  

        
 if(g[i][j]==1 && c[j]<2){

   printf("%d - %d \n", i, j);

   fprintf(datos, "a %d - %d \n", i, j);

   c[j]=c[j]+1;

   arist[j]=1;
}}}


    for(i=1;i<=vertices;i++){

      for(j=1;j<=maxar;j++){ 

           

 if(g[i][j]==1 && c[j]<2 && arist[j]!=0){

   arist[j]=0;

   verti[i]=1;

                         
}}}
    for(i=1;i<=vertices;i++){

      for(j=1;j<=maxar;j++){ 

         if(arist[j]==2){

   verti[i]=1;
           }
      } 
    }                         
                       
    printf("\n Vertices que cubren todas las aristas:\n");
    for(j=1;j<=maxar;j++){

      if(verti[j]==1){
 printf("%d \n", j);                                 }

    }



jueves, 28 de junio de 2012

Cotas del Problema Cobertura de Vértices

Para el problema de la cobertura de vértices necesitamos  minimizar la cantidad de nodos utilizados para cubrir la mayor cantidad de aristas en el grafo.
 

También se podría minimizar la cantidad de aristas utilizadas para cubrir el total de nodos.










La cota superior es una solucion factible para nuestro problema en este caso sería que se cubrieran todos los nodos y vértices esto seria el total vértices y el máximo de aristas permitido.

La cota inferior es una solución ideal mas aproximada a la solución óptima que se justifica con la relación de aristas en cada vértice, es el vértice que tiene la mayor cantidad de "vecinos" y la cantidad de aristas mínima permitida que recibe como argumento bajo la condición que sea mayor al número de vértices.

Código:
printf("Maximo de aristas: %d \n", maxar);
    printf("Densidad: %f \n", densidad);
    int  max=0;
    int v[vertices+1];    
    for(i=1;i<=vertices;i++)    
      {
       v[i]=0;
      }

    for(i=1;i<=vertices;i++)
     {
     for(j=i;j<=maxar;j++)
      {
       g[i][j] = conectado(densidad);  
       if(g[i][j]==1)
        {
         printf("%d - %d \n", i, j);
         fprintf(datos, "a %d - %d \n", i, j);
         v[i]=v[i]+1;
        }   
       }                                                 
      }
    for(i=1;i<=vertices;i++)    
     {
    if(max < v[i])
      {
       max=v[i];
      } 
     }
    for(i=1;i<=vertices;i++)    
     {
      if(v[i]==max)
       {
        max=i;
       }
     }
    printf("\n#Cota inferior = (%d , %d)\n",max,aristas);   
    printf("#Cota superior = (%d , %d)\n",vertices,maxar);
 

miércoles, 27 de junio de 2012

Generador de Instancias el Problema de Cobertura de vértices (Vertex Cover)

Sea m = |E | el número de lados y n = |V | el número de vértices. Se definen las variables binarias: xi es 1 si el vértice está en la cubierta, y 0 en otro caso. El total de variables binarias usadas en n. El objetivo consiste en minimizar

Sujeto a
  • Todo lado tiene al menos un extremo en la cubierta:

ENTRADA: Grafo G.
SALIDA: El menor número k tal que exista una cobertura de vértices S para G de tamaño k.
Equivalentemente, el problema puede definirse como un problema de decisión:

ENTRADA: Grafo G y un entero positivo k.
PREGUNTA: ¿Existe una cobertura de vértices S para G de tamaño menor o igual a k?

Estructuras para representarlo
Matriz de incidencia – El grafo está representado por una matriz de A (aristas) por V (vértices), donde [arista, vértice] contiene la información de la arista (1 – conectado, 0 – no conectado)
Matriz de adyacencia – El grafo está representado por una matriz cuadrada M de tamaño n2, donde n es el número de vértices. Si hay una arista entre un vértice x y un vértice y, entonces el elemento mx,y es 1, de lo contrario, es 0

Tomaremos como datos de entrada
vértices , aristas.




Resultados del Generador:

#include<stdio.h>
#include<time.h>
#include<string.h>
int conectado(float densidad);

main(int argc, char *argv[]){
  
  int vertices;  // Cantidad de vertices
  int aristas;
  int maxar;    // Numero maximo de aristas
  float densidad;
  int i, j, objetos=0;
  char linea[50];
  FILE *datos;
  datos = fopen(argv[1],"r");

  if(datos!=NULL){
    
    printf("\nLeyendo instancia del archivo: %s \n\n", argv[1]);
                
    do{
      
      fgets(linea, 100, datos);
      
      if(strlen(linea)==0){       
        continue;
      }
      if(linea[0]=='#'){
        
      printf("Comentario: %s \n", linea);  
      
      }
      
      if(linea[0]=='a'){
        objetos += 1;      
 printf("%s", linea);
      }
    }while(!feof(datos));             
    printf("Son %d aristas en la instancia. \n", objetos);                                      
  }
  else{
    vertices = atoi(argv[1]);
    aristas = atoi(argv[2]);
    maxar = (vertices*(vertices-1))/2;
    
    if(aristas<vertices || aristas>maxar){
      printf("\n\nError: El numero de aristas no puede ser menor al numero de vertices");
      return 0;
    }
    
    printf("Generando conexiones al azar entre %d vertices y %d aristas \n", vertices, aristas);
    
    datos = fopen("datos.txt","w");
    
    densidad = (float)(2*aristas)/(float)(vertices*(vertices-1));
    
    fprintf(datos, "i %d %d %f\n", vertices, aristas, densidad);
    fprintf(datos, "# Instancia generada para %d vertices y %d aristas \n\n", vertices, aristas);
    
    int g[vertices+1][maxar+1];
    
    printf("Maximo de aristas: %d \n", maxar);
    printf("Densidad: %f \n", densidad);
    srand(time(NULL));
    
    for(i=1;i<=vertices;i++){
      for(j=i;j<=maxar;j++){
 
 g[i][j] = conectado(densidad);  
 if(g[i][j]==1){
   printf("%d - %d \n", i, j);
   fprintf(datos, "a %d - %d \n", i, j);
 }   
      }                                                 
    }
  }
  return 0;
}
int conectado(float densidad){
  
  float num;
  int x;
  
  num = (rand() % 10) + 0;
  num=num/10.00;
    
  if(num>=densidad){
    x=1;
  }else{
    x=0;
  }
  return(x);     
}


Otros generadores de Instancias en Vertex Cover:
http://www.nlsde.buaa.edu.cn/~kexu/benchmarks/graph-benchmarks.htm
http://cs.hbg.psu.edu/benchmarks/vertex_cover.html


Referencias
cobertura de vertices

martes, 26 de junio de 2012

Vertex Cover

El equipo esta formado por:
  • Karen Alduncin Ibarra (calif. esperada: 100)
  • Kevin Darío Pérez Cuéllar (calif. esperada: 90)
  • Ricardo Lopez Porras (calif. esperada: 80)

El Lenguaje que utilizaremos será C y Java.

El problema a analizar será vertex cover (cobertura de vértices) que es un problema NP-completo.
Este problema es muy utilizado en teoría de complejidad computacional para probar la pertenencia a la clase NP-Hard de otros problemas computacionales difíciles.

Por ejemplo:
  • Clique
  • Set covering
  • Circuitos Hamiltonianos

La cobertura de vértices de un grafo no dirigido G = (V,E) es unsubconjunto S de V (el conjunto de vértices) tal que para cada aristaab del conjunto E, ya sea el vértice a o b pertenece a S.


Suponga un grafo no dirigido G = (V, E). Una cubierta de vértices para G es un subconjunto de vértices V' tal que todo lado de E es incidente en al menos un vértice de V'.

El problema de la cobertura de vértices consiste en determinar una cobertura con el mínimo número de vértices.
El problema de poner guardias en los extremos (vértices) de los pasillos (lados) para cubrirlos todos es un problema de cubierta de vértices; el problema abastecer una colonia con el menor número de luminarias también lo es.

Cada vértice cubre su arco incidente y se trata de buscar el conjunto de vértices que cubra todos los arcos. La idea es encontrar la cobertura de vértices de tamaño mínimo.

En el siguiente grafo, {1,3,5,6} es una cobertura de vértices de tamaño 4. Sin embargo, esta no es la cobertura mínima, porque existen las coberturas de vértices {245} {124} y,ambas de tamaño 3 que satisfacen la cobertura.


Para reducir el conjunto independiente de VERTEX COVER sólo tenemos que observar que un conjunto de nodos S es una cubierta de vértices del grafo G = (V, E) (es decir, S toca cada borde en E) si y sólo si los nodos restantes, VS, son un conjunto independiente de G .


Por lo tanto, para resolver una instancia (G, g), del grupo independiente, sólo tiene que buscar una cubierta de vértices de G con JV nodos j g. Si una cubierta de vértices existe, luego tomar todos los nodos no en él. Si no hay tal cubierta de vértices existe, entonces G no puede tener un conjunto independiente de tamaño de g.

Rango de vertices mayor de 100 para el caso de 100 vertices seria d= 0.5 y mmax = 100(100-1)/2 [4950]*0.05 = 247 aristas totales, con las formulas = mmax*d donde d= m / mmax , mmax = n(n-1)/2 para poder ejemplificar como un problema en un grafo no dirigido.


Referencias: