Cátedra Nissan -PROTHIUS- Aplicación de los algoritmos de hormigas para la resolución del problema de equilibrado de líneas de montaje SALBP-E y aplicación a un caso real – Anexo IV: Listado del programa Javier Bretón Blas y Jose Antonio Fernández Ros SW-122/2010 (CN 2010-BF) Departamento de Organización de Empresas Universidad Politécnica de Cataluña Publica: Universitat Politècnica de Catalunya www.upc.edu Edita: Cátedra Nissan www.nissanchair.com director@nissanchair.com TiTOL Aplicación de los algoritmos de hormigas para la resolución del problema de equilibrado de líneas de montaje SALBP-E y aplicacióna un caso real. ALUMNE JavierBretónBlas;Jose AntonioFernándezRos ASSIGNATURA Proyectofinal del carrera PROFESSOR D. JoaquínBautistaValhondo DATA 4 de octubrede 2000 DOCUMENT Anexo lV: Listadosdel programa RESUM Esteanexoincluyeel códigofuenteen Java de las aplicaciones informáticas implementadas para el algoritmode hormigassin mejora,el algoritmode hormigascon mejoray el multi-start, así comola descripción funcional de losobjetosque lasforman. - BARCELONA INDUSTRIAL ES C O L AT É C N IC AS U P E R IORD' ENGINYERIA i ÍNDICE RESUMEN................................................................................................................................ 1 CAPÍTULO 1: ALGORITMO DE HORMIGAS................................................................... 2 1.1 DESCRIPCIÓN DEL PROGRAMA ....................................................................................... 3 1.2 LISTADO DE LOS OBJETOS .............................................................................................. 5 CAPÍTULO 2: ALGORITMO DE LAS HORMIGAS CON MEJORA LOCAL............. 58 2.1 DESCRIPCIÓN DEL PROGRAMA ..................................................................................... 59 2.2 LISTADO DE LOS OBJETOS ............................................................................................ 60 CAPÍTULO 3: MULTI-START............................................................................................. 68 3.1 DESCRIPCIÓN DEL PROGRAMA ..................................................................................... 69 3.2 LISTADO DE OBJETOS ................................................................................................... 70 1 RESUMEN Este anexo incluye el código fuente en Java de las aplicaciones informáticas implementadas para el algoritmo de hormigas sin mejora, el algoritmo de hormigas con mejora y el multistart, así como la descripción funcional de los objetos que las forman. 2 CAPÍTULO 1: ALGORITMO DE HORMIGAS 3 1.1 DESCRIPCIÓN DEL PROGRAMA El programa está formado por 20 objetos con la siguientes características: • Azar: crea una semilla para la extracción de números aleatorios. • CotaSalbpE: cálculo de cotas para el SALBP-E. • CotasTC: calcula la cota máxima de tiempo de ciclo y la mínima. • Cronometro: contador de tiempo de ejecución. • Datos: es el encargado de leer toda la información inicial exterior al programa, así como de crear la lista de sucesores y precedesores inmediatos. • Evaluacion: dada una secuencia de tareas y un tiempo de ciclo máximo y mínimo, calcula la mejor combinación de tiempo de ciclo y número de estaciones para la secuencia. • Hormiga: es el encargado de crear una secuencia de tareas. Instancia al objeto Indices y recoge su información. • Indices: elabora los índices de decisión dada una lista de tareas candidatas y los devuelve para ser utilizados por el objeto Hormiga. • Listas: contiene las listas de sucesores y predecesores inmediatos, así como la lista de candidatas y de predecesores inmediatos asignado. Actualiza las dos últimas listas cada vez que se asigna una tarea a la secuencia. • MatrizPesos: crea la matriz de pesos para cada tarea según los 14 criterios heurísticos. Instancia al objeto CotasTC para calcular una primera cota de tiempo de ciclo máximo, necesaria para algunos criterios heurísticos. • MejorSolucion: contiene la mejor solución global hallada. • NextTarea: dado un criterio heurístico y una lista de candidatas, elige la siguiente tarea. • NextTareaInicial: extensión de NextTarea utilizado por la clase SolucionInicial • Opciones: lee el archivo con opciones y parámetros. • Principal: clase principal (main). Inicializa los parámetros y crea las subcolonias. • Rastros: contiene la matriz de rastros, así como los métodos para su inicialización. Además, crea copias de la matriz, controla la desviación de la solución y restaura la matriz de rastros con la copia creada. • Ristra: contiene la secuencia de tareas en curso. Dada una nueva tarea, actualiza la secuencia. 4 • Salida: métodos para crear los ficheros de salida. • SolucionInicial: crea una solución inicial mediante una heurística Greedy usando los 14 criterios heurísticos. • Subcolonia: instancia el objeto Hormiga, lo inicializa y recoge su información. Con esa información, actualiza la matriz de rastros. 5 1.2 LISTADO DE LOS OBJETOS 1.2.1 Principal public class Principal { public static void main(String arg[]) { int numSubColonia = 0; Subcolonia.numSubcolonia = 0; Cronometro cr = new Cronometro(); cr.inicio(); //Puesta a cero del cronómetro Azar.semilla(); //Inicializa la semilla del random Datos datos = new Datos(arg); datos.importaDatos(); OpcionesTabla op = new OpcionesTabla(arg[4], arg[5]); op.lecturaOpciones(); Salida salida = new Salida(arg[6]); salida.cabecera(); MatrizPesos.inicializa(); CotaSalbpE cota = new CotaSalbpE(); MejorSolucion.inicializa(); Subcolonia.maxsubTC = Datos.TiempoTotal; Subcolonia.mejorsubOBJ = 1000000000; SolucionInicial solini = new SolucionInicial("ID"); solini.lanzaSolucion(); salida.OBJInicial = MejorSolucion.OBJ; Rastros rastro = new Rastros(solini.PaqueteOBJ); rastro.inicializaRastros(); System.out.println(); Subcolonia sub; boolean condicionFinal = false; if(Opciones.tipoLimitacion.equals("HORMIGAS")){ cr.fin(); for(int i=1; (i<=Opciones.limitacion) && (condicionFinal == false); i++){ //Creación subcolonia if((i%2) != 0) sub = new Subcolonia(Opciones.tamano, "ID", i); else sub = new Subcolonia(Opciones.tamano, "DI", i); //Lanzamiento subcolonia sub.lanzaHormigas(); numSubColonia++; sub.actualizaRastros(); 6 //Control de desvición (backtracking) rastro.controlBacktracking(sub.igualado, sub.mejorado, i, sub.Sentido); System.out.print("Hormiga # "+i+" OBJ= "+MejorSolucion.OBJ+" Back= "+ Rastros.contback+"\r"); salida.acumulaSalida(sub); //Escritura de la evolución de //la solución if(MejorSolucion.OBJ == CotaSalbpE.CotaSalbpE) condicionFinal = true; rastro.trasponer(); cr.fin(); } } else if(Opciones.tipoLimitacion.equals("TIEMPO")){ int i=1; cr.fin(); while((cr.tiempo()<=Opciones.limitacion) && ((condicionFinal == false))){ if((i%2) != 0) sub = new Subcolonia(Opciones.tamano, "ID", i); else sub = new Subcolonia(Opciones.tamano, "DI", i); sub.lanzaHormigas(); numSubColonia++; sub.actualizaRastros(); System.out.print("Hormiga # "+i+"\r"); rastro.controlBacktracking(sub.igualado, sub.mejorado, i, sub.Sentido); if(MejorSolucion.OBJ == Datos.OBJOptima) condicionFinal = true; rastro.trasponer(); cr.fin(); //Controla el tiempo que ha transcurrido i++; } } System.out.println(); System.out.println(); System.out.println("MEJOR SOLUCION"); System.out.println("OBJ= "+MejorSolucion.OBJ); System.out.println("N = "+MejorSolucion.N); System.out.println("TC = "+MejorSolucion.TC); cr.fin(); System.out.println(); System.out.println("Tiempo de ejecucion: "+cr.tiempo()+" s"); salida.tablaSalida(numSubColonia, cr.tiempo()); salida.rellenaBlancos(numSubColonia); salida.estacionesSalida(); 7 salida.escribeSalida(); } } 1.2.2 Listas public class Listas { int ListaSuc[][]; int ListaPred[]; int ListaPredAsig[]; int Candidatas[]; int limCandidatas = 0; //Marca el final de la lista de candidatas String Sentido; public Listas(String s) { Sentido = s; // Sentido = ID ó DI copiaListas(); inicializaCandidatas(); } //Crea una copia de trabajo para la hormiga de la lista de sucesoras //y precedesoras inmediatas según el sentido de la hormigo public void copiaListas() { if(Sentido.equals("ID")){ ListaSuc = Datos.ListaSucID; ListaPred = Datos.ListaPredID; } else if(Sentido.equals("DI")){ ListaSuc = Datos.ListaSucDI; ListaPred = Datos.ListaPredDI; } ListaPredAsig = new int[Datos.NumTareas+1]; } //Calcula las candidatas por primera vez: //Aquellas tareas que no tienen precedentes public void inicializaCandidatas() { //Se crea la lista de candidatas Candidatas = new int[Datos.NumTareas+1]; for(int i=1; i<=Datos.NumTareas ; i++){ if(ListaPred[i] == 0){ limCandidatas++; //Aumenta el tamaño de la venta //de la lista de candidatas Candidatas[limCandidatas] = i; } } } 8 //Actualiza la lista de predecesoras inmediatas y la lista de //candidatas dada la nueva tarea asignada y la posicion que //ocupa en la lista de candidatas public void actualizaListas(int TareaPos[]) { //Tareas que van a ser nuevas candidatas int nuevasCandidatas[] = new int[ListaSuc[1].length]; int aux=0; int suc=0; int lookTarea; while((suc<=(ListaSuc[1].length-1)) && (ListaSuc[TareaPos[0]][suc] != 0)){ lookTarea = ListaSuc[TareaPos[0]][suc] ; ListaPredAsig[lookTarea]++; //Aumenta en 1 el número de //predecesoras asigna de la tareas //sucesoras a la asignada if(ListaPred[lookTarea] == ListaPredAsig[lookTarea]){ nuevasCandidatas[aux] = lookTarea; aux++; } suc++; } actualizaCandidata(nuevasCandidatas,ListaSuc[1].length, TareaPos[1]); } public void actualizaCandidata(int nuevas[],int longitud, int posicion) { if(nuevas[0]==0){ //No hay ninguna candidata nueva for(int i=posicion; i<=(limCandidatas-1); i++) Candidatas[i] = Candidatas[i+1]; limCandidatas--; } else { Candidatas[posicion] = nuevas[0]; if(longitud > 1){ int i=1; while((i<=(longitud-1)) && (nuevas[i] !=0)){ Candidatas[limCandidatas+1] = nuevas[i]; limCandidatas++; i++; }; } } } } 1.2.3 Ristra public class Ristra { 9 int RistraT[]; //Secuencias de tareas int contTarea = 1; public int ultimaH; //Última heurística asignada public int ultimaT; //Última tarea asignada public Evaluacion eval; public NextTarea next; public Ristra(String sentido) { RistraT = new int[Datos.NumTareas+1]; ultimaT = 0; next = new NextTarea(sentido); ultimaH = 0; } public void actualizaRistraT(int tarea) { RistraT[contTarea] = tarea; ultimaT = tarea; contTarea++; } public int[] getRistraT() { return RistraT; } public void evaluacionRistra(){ eval = new Evaluacion(RistraT); eval.evalua(); } } 1.2.4 NextTarea public class NextTarea { Listas lista; int heuristica; int ultimaT; //Última tarea asignada // en este vector se guardaran la tarea // y la posicion que que devolvera la funcion int tarea[]= new int[2]; String sentido; //Al constructor hay que pasarle la heuristica para que decida //la siguiente tarea en funcion de dicha heuristica y un String que //solo puede ser ID o DI dependiendo si se quiere un lista //preparada para rellenar una ristra con el problema directo (ID) //o inverso (DI) 10 public NextTarea(String r) { sentido = r; lista = new Listas(sentido); } //Método que devuelve la siguiente tarea y su posición dentro de la //lista de candidatas public int[] getTarea(int h, int u) { heuristica=h; ultimaT=u; if(lista.limCandidatas >=1){ if(sentido.equals("ID")) return eligeTareaID(); else return eligeTareaDI(); } else { tarea[0] = -1; //Condición de final tarea[1] = -1; return tarea; } } public int[] eligeTareaID() { int empates; //Cada fila de la matriz TareaPosAux [k][j] contiene en la //posicion k una para el desempate y en j su posicion //se utiliza la posicion "0" del vector int TareaPosAux[][]= new int[lista.limCandidatas][2]; //Se inicializa el peso maximo y su posicion //(dentro de la lista de candidatas) con la primera candidata TareaPosAux[0][0]=lista.Candidatas[1]; TareaPosAux[0][1]=1; //En la lista de candidatas no se utiliza la //primera posicion se calcula el peso de la tarea //candidata con mayor peso empates=0; for (int i=1; i <= lista.limCandidatas-1; i++ ){ int a=MatrizPesos.MatrizID[heuristica][lista.Candidatas[i+1]]; int c=MatrizPesos.MatrizID[heuristica][2]; int b=MatrizPesos.MatrizID[heuristica][TareaPosAux[0][0]]; if (MatrizPesos.MatrizID[heuristica][lista.Candidatas[i+1]] == MatrizPesos.MatrizID[heuristica][TareaPosAux[0][0]]){ empates++; TareaPosAux[empates][0]=lista.Candidatas[i+1]; TareaPosAux[empates][1]=i+1; } else if(MatrizPesos.MatrizID[heuristica] [lista.Candidatas[i+1]]> MatrizPesos.MatrizID[heuristica][TareaPosAux[0][0]]){ empates=0; 11 TareaPosAux[empates][0]=lista.Candidatas[i+1]; TareaPosAux[empates][1]=i+1; } } //Si el numero de empates es mayor que 0 //se debe desempatar if (empates>0) { //Al método se le pasa la lista de empates //y el numero de empates y devuelve la tarea //despues del desempate tarea = desempate (TareaPosAux,empates); } else if (empates==0){ tarea[0] = TareaPosAux[0][0]; tarea[1] = TareaPosAux[0][1]; } return tarea; } public int[] eligeTareaDI() { int empates; //Cada fila de la matriz TareaPosAux [k][j] contiene //en la posicion k una para el desempate y en j su posicion //se utiliza la posicion "0" del vector int TareaPosAux[][]= new int[lista.limCandidatas][2]; //Se inicializa el peso maximo y su posicion //(dentro de la lista de candidatas) con la primera candidata TareaPosAux[0][0]=lista.Candidatas[1]; TareaPosAux[0][1]=1; //En la lista de candidatas no se utiliza la //primera posicion se calcula el peso de la tarea //candidata con mayor peso empates=0; for (int i=1; i <= lista.limCandidatas-1; i++ ){ if (MatrizPesos.MatrizDI[heuristica][lista.Candidatas[i+1]] == MatrizPesos.MatrizDI[heuristica][TareaPosAux[0][0]]){ empates++; TareaPosAux[empates][0]=lista.Candidatas[i+1]; TareaPosAux[empates][1]=i+1; } else if (MatrizPesos.MatrizDI[heuristica] [lista.Candidatas[i+1]]> MatrizPesos.MatrizDI[heuristica][TareaPosAux[0][0]]){ empates=0; TareaPosAux[empates][0]=lista.Candidatas[i+1]; TareaPosAux[empates][1]=i+1; } } //Si el numero de empates es mayor que 0 //se debe desempatar if (empates>0) { 12 //Al método se le pasa la lista de empates y el numero //de empates y devuelve la tarea despues del desempate tarea = desempate (TareaPosAux,empates); } else if (empates==0){ tarea[0] = TareaPosAux[0][0]; tarea[1] = TareaPosAux[0][1]; } return tarea; } public int[] desempate (int TareaPosAux[][],int empates) { int empatesRastro; int tareaPos[] = new int[2]; //Vector donde se guardan las tareas con el rastro maximo, //si existen mas de 1, se escogerá una al azar double sameRastro[][] = new double [empates+1][3]; sameRastro[0][0] = TareaPosAux[0][0]; sameRastro[0][1] = TareaPosAux[0][1]; sameRastro[0][2] = Rastros.Tareas[ultimaT][TareaPosAux[0][0]]; empatesRastro=0; for (int i=0; i <= empates-1; i++){ if (Rastros.Tareas[ultimaT][TareaPosAux[i+1][0]] == Rastros.Tareas[ultimaT][(int)(sameRastro[0][0])]){ empatesRastro++; sameRastro[empatesRastro][0] = TareaPosAux[i+1][0]; sameRastro[empatesRastro][1] = TareaPosAux[i+1][1]; sameRastro[empatesRastro][2] = Rastros.Tareas[ultimaT] [TareaPosAux[i+1][0]]; } else if (Rastros.Tareas[ultimaT][TareaPosAux[i+1][0]]> Rastros.Tareas[ultimaT][(int)(sameRastro[0][0])]){ empatesRastro=0; sameRastro[empatesRastro][0]=TareaPosAux[i+1][0]; sameRastro[empatesRastro][1]=TareaPosAux[i+1][1]; sameRastro[empatesRastro][2]= Rastros.Tareas[ultimaT][TareaPosAux[i+1][0]]; } } if (empatesRastro>0) { int azar; azar = Azar.nextInt(0,empatesRastro); tarea[0] = (int) (sameRastro[azar][0]); tarea[1] = (int) (sameRastro[azar][1]); } else if (empatesRastro==0){ tarea[0] = (int) (sameRastro[0][0]); tarea[1] = (int) (sameRastro[0][1]); }else if (empatesRastro < 0) System.out.println("error en Next Tarea Desempate: 13 empates rastro menor que 0"); return tarea; } } 1.2.5 SoluciónInicial public class SolucionInicial { String sentido; int tareapos[]; Ristra ristra; NextTareaInicial next; int PaqueteRistras[][]; int PaqueteOBJ[]; int numAnt; public SolucionInicial(String sentido) { this.sentido = sentido; PaqueteOBJ = new int[15]; PaqueteRistras = new int[15][Datos.NumTareas+1]; numAnt = 1; } public void lanzaSolucion() { for(int h=1; h<=14; h++){ creaSolucion(h); recogeInformacion(); comparaInformacion(); numAnt++; } System.out.println(); System.out.println("MEJOR SOLUCION INICIAL"); System.out.println("OBJ= "+MejorSolucion.OBJ); System.out.println("N = "+MejorSolucion.N); System.out.println("TC = "+MejorSolucion.TC); } public void creaSolucion(int h) { tareapos = new int[2]; ristra = new Ristra(sentido); next = new NextTareaInicial(sentido); for(int i=1; i<=Datos.NumTareas; i++){ tareapos = next.getTarea(h, ristra.ultimaT); ristra.actualizaRistraT(tareapos[0]); next.lista.actualizaListas(tareapos); } 14 ristra.evaluacionRistra(); } public void recogeInformacion() { for(int i=1; i<=Datos.NumTareas; i++) PaqueteRistras[numAnt][i] = ristra.RistraT[i]; PaqueteOBJ[numAnt] = ristra.eval.getObj(); } public void comparaInformacion() { if(PaqueteOBJ[numAnt] < MejorSolucion.OBJ){ MejorSolucion.OBJ = PaqueteOBJ[numAnt]; MejorSolucion.N = ristra.eval.getNumEst(); MejorSolucion.TC = ristra.eval.getTC(); for(int i=1; i<=Datos.NumTareas; i++) MejorSolucion.Ristra[i] = PaqueteRistras[numAnt][i]; MejorSolucion.sentidoHormiga = "ID"; } } } 1.2.6 NextTareaInicial public class NextTareaInicial extends NextTarea { public NextTareaInicial(String r) { super(r); lista = new Listas(sentido); } public int[] desempate (int TareaPosAux[][],int empates) { int i=1; int tareaPos[] = new int[2]; tareaPos[0]=TareaPosAux[0][0]; tareaPos[1]=TareaPosAux[0][1]; for (i=1; i <= empates ; i++){ if(sentido.equals("ID")){ if (TareaPosAux[i][0] < tareaPos[0]){ tareaPos[0] = TareaPosAux[i][0]; tareaPos[1] = TareaPosAux[i][1]; } } else { if (TareaPosAux[i][0] > tareaPos[0]){ tareaPos[0] = TareaPosAux[i][0]; tareaPos[1] = TareaPosAux[i][1]; } } } 15 return tareaPos; } } 1.2.7 Indices import java.math.*; public class Indices { int HeuIntrinseca; //Heurística intrínseca a la hormiga double VectorIndices[]; //Índices de decisión int t[][]; //Tarea asociada a la heurística elegida //y su posición en la lista de candidatas Ristra ristra; String tipo; int limCandidatas; public Indices(int i) { HeuIntrinseca = i; } public int[] eligeTarea(Ristra r, String t) { ristra = r; tipo = t; limCandidatas = ristra.next.lista.limCandidatas; VectorIndices = new double[limCandidatas+1]; VectorIndices = calculoIndices(); if(tipo.equals("ALEA")) return sorteo(); else return maximo(); } //Calcula los índices de decisión public double[] calculoIndices() { double vectorAux[] = new double[limCandidatas+1]; double sumaDenominador = 0; int ph[] = new int[limCandidatas+1]; //Peso de la tarea con la //heurística intrínseca int sumaph = 0; //Denominador para ponderar los ph double sumaRastro = (double) (0.0); //Denominador para ponderar //los rastros for(int i=1; i<=limCandidatas; i++){ int taux; //Tarea de la posicion i de la lista de candidatas taux = ristra.next.lista.Candidatas[i]; ph[i] = Hormiga.Pesos[HeuIntrinseca][taux]; sumaph += ph[i]; sumaRastro += Rastros.Tareas[ristra.ultimaT][taux]; } 16 //Índices sin acumulación if(Opciones.ponderacionIndices.equals("SI")){ for(int i=1; i<=limCandidatas; i++){ int taux; //Tarea de la posicion i de //la lista de candidatas taux = ristra.next.lista.Candidatas[i]; vectorAux[i] = (Math.pow(100* (Rastros.Tareas[ristra.ultimaT][taux])/ sumaRastro,Opciones.alfa)) * Math.pow(100*((double)(ph[i])/ (double)(sumaph)), Opciones.beta)); sumaDenominador += vectorAux[i]; } } else if(Opciones.ponderacionIndices.equals("NO")){ for(int i=1; i<=limCandidatas; i++){ int taux; taux = ristra.next.lista.Candidatas[i]; vectorAux[i] = (Math.pow( (Rastros.Tareas[ristra.ultimaT][taux]), Opciones.alfa)) * (Math.pow((double)(ph[i]), Opciones.beta)); sumaDenominador += vectorAux[i]; } } else System.out.println("ERROR: Elegir si hay o no índices de ponderación"); if(tipo.equals("ALEA")){ VectorIndices[0] = 0; for(int i=1; i<=limCandidatas; i++) VectorIndices[i] = VectorIndices[i-1] + vectorAux[i]/sumaDenominador; } else { for(int i=1; i<=limCandidatas; i++) VectorIndices[i] = vectorAux[i]; } return VectorIndices; } public int[] sorteo(){ int cand = limCandidatas; //Nº candidata escogida en el sorteo //cand=limCanditas al inicio para //asegurar la candidata //en caso de que rand sea igual a 1 double rand = Azar.aleatorio.nextDouble(); for(int i=1; i<=limCandidatas; i++){ if((rand >= VectorIndices[i-1]) && (rand < VectorIndices[i])){ cand = i; i = limCandidatas+1; //Marca para salir del bucle } } 17 int tareapos[] = new int[2]; tareapos[0] = ristra.next.lista.Candidatas[cand]; tareapos[1] = cand; return tareapos; } public int[] maximo(){ int cand = 1; //Tarea escogida por ser la de mayor índice for(int i=2; i<=limCandidatas; i++){ if(VectorIndices[i]>VectorIndices[cand]) cand = i; } int tareapos[] = new int[2]; tareapos[0] = ristra.next.lista.Candidatas[cand]; tareapos[1] = cand; return tareapos; } } 1.2.8 Hormiga import java.math.*; public class Hormiga { Ristra ristra; Indices indices; int heuIntrinseca; String sentido; String tipo; static int Pesos[][]; //Matriz de pesos estandarizada public Hormiga(int h, String s, String t) { heuIntrinseca = h; //Heurística intrínseca sentido = s; //Dirección: ID ó DI tipo = t; //Aleatoria o pseudo-aleatoria ristra = new Ristra(sentido); indices = new Indices(heuIntrinseca); if(sentido.equals("ID")) Pesos = MatrizPesos.MatrizID; else Pesos = MatrizPesos.MatrizDI; } public void construirSolucion() { 18 //Opción según hormigas aleatorias o pseudo-aleatorias if(tipo.equals("ALEA")) aleatorio(1, Datos.NumTareas); else if(tipo.equals("PSEUDO")) pseudoAleatorio(); ristra.evaluacionRistra(); } public void aleatorio(int inicio, int fin) { int tareapos[]; //Tarea elegida for(int i=inicio; i<=fin; i++){ tareapos = indices.eligeTarea(ristra, "ALEA"); //Se añade la tarea a la secuencia de tareas ristra.actualizaRistraT(tareapos[0]); //Se actualiza la lista de candidatas ristra.next.lista.actualizaListas(tareapos); } } public void pseudoAleatorio() { int tareapos[] = new int[2]; //Tarea elegida double rand; //Índice para el sorteo pesudo-aleatorio for(int cont=1; cont<=Datos.NumTareas; cont++){ rand = Math.random(); if(rand>Opciones.indicePseudo) //Elige ser aleatorio aleatorio(cont, cont); else { //Elige ser pseudo-aleatorio tareapos = indices.eligeTarea(ristra, "PSEUDO"); ristra.actualizaRistraT(tareapos[0]); ristra.next.lista.actualizaListas(tareapos); } } } } 1.2.9 Evaluacion import java.math.*; public class Evaluacion { private int Ristra[]; private int Obj, TC, NumEst; String mejorSentido; 19 public Evaluacion(int ris[]) { Ristra = ris; } public void evalua() { mejorSentido = "ID"; evaluaID(); evaluaDI(); MejorSolucion.sentidoEval = mejorSentido; } public void evaluaID() { int TC2 = CotasTC.CotaMinTC; Obj = 1000000000; int tacum, tasig, TCajust2, n2, TCnext; int i, r; int marca, cota2; int obj2 = Obj+1; //Se pone porque hay que inicilizarla!!! do{ //loop de tiempos de ciclo tacum = 0; tasig = 0; TCajust2 = 0; n2 = 1; r = 1; marca = 0; cota2 = 1; TCnext = 1000000000; Salida.numSol++; //Contador del número de soluciones evaluadas do{ //loop de r i = Ristra[r]; tacum += Datos.Tiempos[i]; if(tacum > TC2){ if((tacum-Datos.Tiempos[i]) > TCajust2) TCajust2 = tacum-Datos.Tiempos[i]; if(tacum < TCnext) TCnext = tacum; tasig = tasig + tacum - Datos.Tiempos[i]; tacum = Datos.Tiempos[i]; n2 += 1; if((n2-1+ (int)Math.floor((double)(Datos.TiempoTotaltasig)/TC2))*TCajust2 >= Subcolonia.mejorsubOBJ) cota2 = 0; } if(r==Datos.NumTareas) marca = 1; r++; } while((r<=Datos.NumTareas) && (n2*TCajust2<Subcolonia.mejorsubOBJ) && (cota2>0) && (n2<=Datos.NumEstMax)); 20 if(tacum>TCajust2) {TCajust2 = tacum;} if(TC2 == Datos.TiempoTotal) {TCajust2 = TC2;} if((marca==1) && n2<=Datos.NumEstMax) {obj2 = TCajust2*n2;} else if((marca==0) || n2>Datos.NumEstMax) {obj2 = Obj +1;} if(n2<=Datos.NumEstMax){ if(n2 > Datos.NumEstMin){ if((obj2 <= Obj) && (marca==1)){ Obj = obj2; TC = TCajust2; NumEst = n2; Subcolonia.mejorsubOBJ = Obj; } TC2 = TCnext; } else if(n2 == Datos.NumEstMin){ if(marca == 1){ if(TCajust2<CotasTC.CotaMaxTC){ CotasTC.CotaMaxTC = TCajust2; MatrizPesos.actualizaPesos(); } if(TCajust2<Subcolonia.maxsubTC){ Subcolonia.maxsubTC = TCajust2; } if(obj2 <= Obj){ Obj = obj2; TC = TCajust2; NumEst = n2; Subcolonia.mejorsubOBJ = Obj; } TC2 = Datos.TiempoTotal+1; } else if(marca == 0){ if((Datos.TiempoTotal-tasig)<=TC2){ if((Datos.TiempoTotal-tasig)>TCajust2) TCajust2 = Datos.TiempoTotal-tasig; obj2 = n2*TCajust2; if(obj2 <= Obj){ Obj = obj2; TC = TCajust2; NumEst = n2; Subcolonia.mejorsubOBJ = Obj; } if(TCajust2<CotasTC.CotaMaxTC){ CotasTC.CotaMaxTC = TCajust2; MatrizPesos.actualizaPesos(); } if(TCajust2<Subcolonia.maxsubTC){ Subcolonia.maxsubTC = TCajust2; } TC2 = Datos.TiempoTotal+1; } else if((Datos.TiempoTotal-tasig)>TC2) TC2 = TCnext; } } else if(n2<Datos.NumEstMin){ if(marca == 1) TC2 = Datos.TiempoTotal+1; else if(marca == 0){ 21 if((n2-1+(int)Math.floor( (double)(Datos.TiempoTotal-tasig)/TC2)) > Datos.NumEstMin) TC2 = TCnext; else if((n2-1+(int)Math.floor( (double)(Datos.TiempoTotal-tasig)/TC2)) <= Datos.NumEstMin) TC2 = Datos.TiempoTotal+1; } } } else TC2 = TCnext; } while(TC2 <= Subcolonia.maxsubTC); } public void evaluaDI() { int TC2 = CotasTC.CotaMinTC; int tacum, tasig, TCajust2, n2, TCnext; int i, r; int marca, cota2; int obj2 = Obj+1; //Se pone porque hay que inicilizarla!!! do{ //loop de tiempos de ciclo tacum = 0; tasig = 0; TCajust2 = 0; n2 = 1; r = 1; marca = 0; cota2 = 1; TCnext = 1000000000; Salida.numSol++; //Contador del número de soluciones evaluadas do{ //loop de r i = Ristra[r]; tacum += Datos.Tiempos[i]; if(tacum > TC2){ if((tacum-Datos.Tiempos[i]) > TCajust2) TCajust2 = tacum-Datos.Tiempos[i]; if(tacum < TCnext) TCnext = tacum; tasig = tasig + tacum - Datos.Tiempos[i]; tacum = Datos.Tiempos[i]; n2 += 1; if((n2-1+ (int)Math.floor((double)(Datos.TiempoTotaltasig)/TC2))*TCajust2 >= Subcolonia.mejorsubOBJ) cota2 = 0; } if(r==Datos.NumTareas) marca = 1; r++; } while((r<=Datos.NumTareas) && (n2*TCajust2<Subcolonia.mejorsubOBJ) && (cota2>0) && (n2<=Datos.NumEstMax)); 22 if(tacum>TCajust2) {TCajust2 = tacum;} if(TC2 == Datos.TiempoTotal) {TCajust2 = TC2;} if((marca==1) && n2<=Datos.NumEstMax) {obj2 = TCajust2*n2;} else if((marca==0) || n2>Datos.NumEstMax) {obj2 = Obj +1;} if(n2<=Datos.NumEstMax){ if(n2 > Datos.NumEstMin){ if((obj2 <= Obj) && (marca==1)){ Obj = obj2; TC = TCajust2; NumEst = n2; mejorSentido = "DI"; Subcolonia.mejorsubOBJ = Obj; } TC2 = TCnext; } else if(n2 == Datos.NumEstMin){ if(marca == 1){ if(TCajust2<CotasTC.CotaMaxTC){ CotasTC.CotaMaxTC = TCajust2; MatrizPesos.actualizaPesos(); } if(TCajust2<Subcolonia.maxsubTC){ Subcolonia.maxsubTC = TCajust2; } if(obj2 <= Obj){ Obj = obj2; TC = TCajust2; NumEst = n2; mejorSentido = "DI"; Subcolonia.mejorsubOBJ = Obj; } TC2 = Datos.TiempoTotal+1; } else if(marca == 0){ if((Datos.TiempoTotal-tasig)<=TC2){ if((Datos.TiempoTotal-tasig)>TCajust2) TCajust2 = Datos.TiempoTotal-tasig; obj2 = n2*TCajust2; if(obj2 <= Obj){ Obj = obj2; TC = TCajust2; NumEst = n2; mejorSentido = "DI"; Subcolonia.mejorsubOBJ = Obj; } if(TCajust2<CotasTC.CotaMaxTC){ CotasTC.CotaMaxTC = TCajust2; MatrizPesos.actualizaPesos(); } if(TCajust2<Subcolonia.maxsubTC){ Subcolonia.maxsubTC = TCajust2; } TC2 = Datos.TiempoTotal+1; } else if((Datos.TiempoTotal-tasig)>TC2) TC2 = TCnext; } } else if(n2<Datos.NumEstMin){ 23 if(marca == 1) TC2 = Datos.TiempoTotal+1; else if(marca == 0){ if((n2-1+(int)Math.floor( (double)(Datos.TiempoTotal-tasig)/TC2)) > Datos.NumEstMin) TC2 = TCnext; else if((n2-1+(int)Math.floor( (double)(Datos.TiempoTotal-tasig)/TC2)) <= Datos.NumEstMin) TC2 = Datos.TiempoTotal+1; } } } else TC2 = TCnext; } while(TC2 <= Subcolonia.maxsubTC); } public int getObj(){ return Obj; } public int getTC(){ return TC; } public int getNumEst(){ return NumEst; } } 1.2.10 Rastros import java.math.*; public class Rastros { static double[][] Tareas; int[] solini; int contBacktracking, auxBacktracking; double[][] copiaTareas; static int contback; public Rastros(int[] s) { solini = s; Tareas = new double[Datos.NumTareas+1][Datos.NumTareas+1]; copiaTareas = new double[Datos.NumTareas+1][Datos.NumTareas+1]; contBacktracking = 0; auxBacktracking = 0; contback = 0; } public void inicializaRastros() 24 { if(Opciones.tipoRastro.equals("CONSTANTE")) constante(); else if(Opciones.tipoRastro.equals("ALEATORIO")) aleatorio(); } public void constante() { for(int i=0; i<=Datos.getNumTareas(); i++){ for(int j=0; j<=Datos.getNumTareas(); j++){ Tareas[i][j] = Opciones.rastroInicial; } } } public void aleatorio() { for(int i=0; i<=Datos.getNumTareas(); i++){ for(int j=0; j<=Datos.getNumTareas(); j++){ Tareas[i][j] = Azar.aleatorio.nextInt(); } } } public void trasponer() { double aux; for(int i=0; i<=Datos.NumTareas; i++){ for(int j=i+1; j<=Datos.NumTareas; j++){ aux = Tareas[i][j]; Tareas[i][j] = Tareas[j][i]; Tareas[j][i] = aux; } } } //Hace una copia de la Matriz de Rastros //para poder restaurarla en caso de backtracking public void copiaRastro(String sentido) { //La matriz de copia siempre se guarda en sentido ID if(sentido.equals("ID")){ for(int i=0; i<=Datos.NumTareas; i++){ for(int j=0; j<=Datos.NumTareas; j++) copiaTareas[i][j] = Tareas[i][j]; } } else { for(int i=0; i<=Datos.NumTareas; i++){ for(int j=0; j<=Datos.NumTareas; j++) 25 copiaTareas[i][j] = Tareas[j][i]; } } } //Sustituye la matriz actual por la //copia guardada por copiaRastro() public void restauraRastro(String sentido) { //La matriz de copia siempre se guarda en sentido ID if(sentido.equals("ID")){ for(int i=0; i<=Datos.NumTareas; i++){ for(int j=0; j<=Datos.NumTareas; j++) Tareas[i][j] = copiaTareas[i][j]; } } else { for(int i=0; i<=Datos.NumTareas; i++){ for(int j=0; j<=Datos.NumTareas; j++) Tareas[i][j] = copiaTareas[j][i]; } } } //Controla la desviación de las soluciones //y decide si es necesario un backtracking public void controlBacktracking(boolean igualado, boolean mejorado, int subcolonia, String sentido) { if(igualado == true) contBacktracking++; if(mejorado == true){ auxBacktracking = subcolonia; contBacktracking = 1; copiaRastro(sentido); } if(subcolonia > (auxBacktracking+100)){ if(contBacktracking < 40){ restauraRastro(sentido); contback++; } auxBacktracking = subcolonia; contBacktracking = 0; } } } 1.2.11 Subcolonia public class Subcolonia { int tamano; //1 ó 14 String Sentido; 26 Hormiga ant; int numAnt = 0; double b; boolean marcaMejor = false; //true si la mejor hormiga mejora //o iguala la OBJ global boolean marcaMejorSolo = false; //true si la mejor hormiga //mejora la OBJ global boolean mejorado, igualado; //Parámetros para el control //de backtracking static int mejorsubOBJ; static int maxsubTC; static int numSubcolonia; MejoraLocal mejora; //Atributos para la recolección de información int PaqueteRistras[][]; int PaqueteOBJ[]; int PaqueteN[]; int PaqueteTC[]; int numSub; public Subcolonia(int t, String s, int n) { tamano = t; Sentido = s; PaqueteOBJ = new int[14]; PaqueteRistras = new int[14][Datos.NumTareas+1]; PaqueteN = new int[14]; PaqueteTC = new int[14]; MatrizPesos.actualizaPesoAzar(Sentido); mejorsubOBJ = 2000000000; maxsubTC = Datos.TiempoTotal; rastretes = Rastros.Tareas; numSub = n; igualado = false; mejorado = false; } public void lanzaHormigas() { for(int i=1; i<=14; i++){ ant = new Hormiga(i, Sentido, Opciones.tipoHormiga); ant.construirSolucion(); recogeInformacion(); comparaInformacion(); numAnt++; } numSubcolonia++; } 27 public void recogeInformacion() { for(int i=1; i<=Datos.NumTareas; i++) PaqueteRistras[numAnt][i] = ant.ristra.RistraT[i]; PaqueteOBJ[numAnt] = ant.ristra.eval.getObj(); PaqueteN[numAnt] = ant.ristra.eval.getNumEst(); PaqueteTC[numAnt] = ant.ristra.eval.getTC(); } public void comparaInformacion() { if(PaqueteOBJ[numAnt] < MejorSolucion.OBJ){ MejorSolucion.OBJ = PaqueteOBJ[numAnt]; MejorSolucion.N = PaqueteN[numAnt]; MejorSolucion.TC = PaqueteTC[numAnt]; for(int i=1; i<=Datos.NumTareas; i++) MejorSolucion.Ristra[i] = PaqueteRistras[numAnt][i]; MejorSolucion.sentidoHormiga = Sentido; MejorSolucion.sentidoEval = ant.ristra.eval.mejorSentido; marcaMejorSolo = true; mejorado = true; } if(PaqueteOBJ[numAnt] <= MejorSolucion.OBJ){ marcaMejor = true; igualado = true; } } public void actualizaRastros() { evaporaRastros(); actualizaTareas(); } public void actualizaTareas() { double unidadRastro[] = new double[15]; double sumaOBJ = 0; int tareaA, tareaB; if(tamano == 14){ //Dejan rastro todas las hormigas for(int i=0; i<=13; i++){ b = 100.0*(((double)(PaqueteOBJ[i])(double)(Datos.TiempoTotal))/ ((double)(Datos.TiempoTotal))); unidadRastro[i] = 1/(Math.pow(b, 1.0)); } for(int contAnt = 0; contAnt<=13; contAnt++){ tareaA = 0; 28 for(int r=1; r<=Datos.NumTareas; r++){ tareaB = PaqueteRistras[contAnt][r]; Rastros.Tareas[tareaA][tareaB] += unidadRastro[contAnt]; tareaA = tareaB; } } } //Sólo dejan rastro las mejores hormigas int minOBJ[] = new int[14]; //Contiene las hormigas con mejor OBJ int limAnt = 0; minOBJ[0] = 0; for(int contAnt=1; contAnt<=13; contAnt++){ if(PaqueteOBJ[contAnt]<PaqueteOBJ[minOBJ[0]]){ minOBJ[0] = contAnt; limAnt = 0; } else if(PaqueteOBJ[contAnt]==PaqueteOBJ[minOBJ[0]]){ minOBJ[limAnt+1] = contAnt; limAnt++; } } if(marcaMejor == true){ //La mejor hormiga mejora o //iguala la OBJ global for(int i=0; i<=limAnt; i++){ tareaA = 0; for(int r=1; r<=Datos.NumTareas; r++){ tareaB = PaqueteRistras[minOBJ[i]][r]; double maxRastro = 0.0; //Se busca el máximo rastro for(int j=0; j<=Datos.NumTareas; j++){ if(Rastros.Tareas[tareaA][j] > maxRastro) maxRastro = Rastros.Tareas[tareaA][j]; } //Rastro extra if(marcaMejorSolo == true){ for(int j=0; j<=Datos.NumTareas; j++) Rastros.Tareas[tareaA][j] *= (1-Opciones.evaporacionExtra); maxRastro *= Opciones.rastroExtra; } //Iguala el máximo rastro Rastros.Tareas[tareaA][tareaB] = maxRastro; tareaA = tareaB; } if(marcaMejorSolo == true){ //Última tarea de la secuencia double maxRastro = 0.0; for(int j=0; j<=Datos.NumTareas; j++){ //Se busca el máximo rastro if(Rastros.Tareas[tareaA][j] > maxRastro) maxRastro = Rastros.Tareas[tareaA][j]; } for(int pos=0; pos<=Datos.NumTareas; pos++) //Evaporación extra de la fila de la 29 //última tarea de la ristra Rastros.Tareas[tareaA][pos] *= (1-Opciones.evaporacionExtra); maxRastro *= Opciones.rastroExtra; Rastros.Tareas[tareaA][0] = maxRastro; marcaMejorSolo = false; //Ya no entra más, sólo evapora //la primera hormiga } } } for(int i=0; i<=limAnt; i++){ b = 100.0*(((double)(PaqueteOBJ[minOBJ[i]])((double)(CotaSalbpE.CotaSalbpE)))/ ((double)(CotaSalbpE.CotaSalbpE))); double unidad = 1/(Math.pow(b, 2.0)); tareaA = 0; for(int r=1; r<=Datos.NumTareas; r++){ tareaB = PaqueteRistras[minOBJ[i]][r]; Rastros.Tareas[tareaA][tareaB] += unidad; tareaA = tareaB; } Rastros.Tareas[tareaA][0] += unidad; //Rastro entre la última tarea de la ristra //y la tarea 0 en sentido contrario } } public void evaporaRastros() { for(int i=0; i<=Datos.NumTareas; i++){ for(int j=0; j<=Datos.NumTareas; j++) Rastros.Tareas[i][j] = Rastros.Tareas[i][j]* (1.0-Opciones.evaporacion); } } } 1.2.12 Opciones import java.io.*; import java.util.*; public class Opciones { private String fichero; static double alfa; static double beta; static double evaporacion ; 30 static static static static static static static static static static static static double evaporacionExtra; double rastroExtra; int tamano; String tipoHormiga; double indicePseudo; String sentido; double rastroInicial; double coefDifusion; String tipoRastro; String tipoLimitacion; int limitacion; String ponderacionIndices; public Opciones(String f) { fichero = f; } public void lecturaOpciones() { try{ String descripcion; BufferedReader inbr = new BufferedReader( new FileReader(fichero)); String inString = inbr.readLine(); StringTokenizer st = new StringTokenizer(inString); descripcion = st.nextToken(); while(!descripcion.equals("fin")){ if(descripcion.equals("alfa")) alfa = Double.valueOf( st.nextToken().trim()).doubleValue(); else if(descripcion.equals("beta")) beta = Double.valueOf( st.nextToken().trim()).doubleValue(); else if(descripcion.equals("evaporacion")) evaporacion = Double.valueOf( st.nextToken().trim()).doubleValue(); else if(descripcion.equals("evaporacionExtra")) evaporacionExtra = Double.valueOf( st.nextToken().trim()).doubleValue(); else if(descripcion.equals("rastroExtra")) rastroExtra = Double.valueOf( st.nextToken().trim()).doubleValue(); else if(descripcion.equals("tipoHormiga")){ tipoHormiga = st.nextToken(); if(tipoHormiga.equals("PSEUDO")) indicePseudo = Double.valueOf( st.nextToken().trim()).doubleValue(); } else if(descripcion.equals("sentido")) sentido = st.nextToken(); else if(descripcion.equals("tamano")) tamano = Integer.valueOf( st.nextToken().trim()).intValue(); 31 else if(descripcion.equals("rastroInicial")){ tipoRastro = st.nextToken(); if(tipoRastro.equals("CONSTANTE")) rastroInicial = Double.valueOf( st.nextToken().trim()).doubleValue(); if(tipoRastro.equals("DIFUSION")) coefDifusion = Double.valueOf( st.nextToken().trim()).doubleValue(); } else if(descripcion.equals("limitacion")){ tipoLimitacion = st.nextToken(); limitacion = Integer.valueOf( st.nextToken().trim()).intValue(); } else if(descripcion.equals("ponderacionIndices")) ponderacionIndices = st.nextToken(); inString = inbr.readLine(); st = new StringTokenizer(inString); descripcion = st.nextToken(); } } catch(EOFException e) { System.out.println("End of stream encountered"); } catch(FileNotFoundException e) { System.out.println("File Not Found:" + fichero); } catch(IOException e){ System.out.println("IO Exception"); } } } 1.2.13 Datos import java.io.*; import java.util.*; public class Datos { static int NumTareas; static int NumEstMin, NumEstMax; static int Tiempos[]; static int MatrizSucI[][]; static int MatrizSuc[][]; static int MatrizPre[][]; static int ListaSucID[][]; static int ListaSucDI[][]; static int ListaPredID[]; static int ListaPredDI[]; static int TiempoTotal; static int TiempoMax; static int OBJOptima; private String argumentos[]; public Datos(String a[]) { argumentos=a; NumEstMin = Integer.valueOf(argumentos[1].trim()).intValue(); NumEstMax = Integer.valueOf(argumentos[2].trim()).intValue(); 32 OBJOptima = Integer.valueOf(argumentos[3].trim()).intValue(); } public void importaDatos(){ try{ //Lectura del número de tareas (NumTareas) BufferedReader inbr = new BufferedReader( new FileReader(argumentos[0])); NumTareas = Integer.valueOf(inbr.readLine().trim()).intValue(); //Lectura de los tiempos de las tareas (Tiempos[]) Tiempos = new int[NumTareas+1]; for(int i=1;i<=NumTareas;i++){ Tiempos[i]= (Integer.valueOf(inbr.readLine().trim()).intValue()); } //Cálculo del número máximo de sucesores ID //y relleno MatrizSucI inbr.mark(1000000); MatrizSucI = new int[NumTareas+1][NumTareas+1]; int NumSucID=0; NumSucID = getNumSucID(inbr); //Inicilizar la matriz ListaPred y ListaSuc ID inicializaMatrices(NumSucID, ListaSucID, ListaPredID); //Se llena la lista de sucesores y precedesores ID inbr.reset(); llenaListaID(inbr, NumSucID); inbr.close(); //Cálculo del número máximo de sucesores DI int NumSucDI = 0; NumSucDI = getNumSucDI(); //Inicializa la matriz ListaPred Y ListaSuc ID inicializaMatrices(NumSucDI, ListaSucDI, ListaPredDI); //Se llena la lista de sucesores y predecesores DI llenaListaDI(NumSucDI, NumSucID); //Calcula la suma total de tiempos TiempoTotal = sumaTiempos(); } catch(EOFException e) { System.out.println("End of stream encountered"); } catch(FileNotFoundException e) { System.out.println("File Not Found:" + argumentos[0]); } catch(IOException e){ System.out.println("IO Exception"); } 33 } //Método que devuelve el número máximo de sucesores ID //a partir del stream de lectura directo del fichero public int getNumSucID(BufferedReader inbr) throws IOException { String inString = inbr.readLine(); StringTokenizer st = new StringTokenizer(inString); for(int i=1; i<=NumTareas ; i++) MatrizSucI[i][i] = 1; int a, b, aux, NumSucID=0, NumSucAux=1; a = Integer.valueOf(st.nextToken().trim()).intValue(); aux = Integer.valueOf(st.nextToken().trim()).intValue(); MatrizSucI[a][aux]=1; inString = inbr.readLine(); st = new StringTokenizer(inString); b=Integer.valueOf(st.nextToken().trim()).intValue(); aux = Integer.valueOf(st.nextToken().trim()).intValue(); while(aux != -1){ MatrizSucI[b][aux]=1; if(a==b){ NumSucAux++; } else { a=b; if(NumSucAux>NumSucID){ NumSucID=NumSucAux; } NumSucAux=1; } inString = inbr.readLine(); st = new StringTokenizer(inString); b = Integer.valueOf(st.nextToken().trim()).intValue(); aux = Integer.valueOf(st.nextToken().trim()).intValue(); } if(NumSucAux > NumSucID) NumSucID = NumSucAux; return(NumSucID); } //Inicializa a cero todos los valores de las //Listas de Sucesores y Predecedorestanto de ID como de DI public void inicializaMatrices(int NumSuc, int ListaSuc[][], int ListaPred[]) { ListaSuc = new int[NumTareas+1][NumSuc]; ListaPred = new int[NumTareas+1]; 34 for(int i=0; i<=NumTareas; i++){ ListaPred[i]=0; for(int j=0;j<=(NumSuc-1);j++) ListaSuc[i][j]=0; } } //Crea y llena las listas de predecesores y sucesores a partir del //stream de entrada del fichero sabiendo el número máximo de sucesores. public void llenaListaID(BufferedReader inbr, int NumSuc) throws IOException { ListaSucID = new int[NumTareas+1][NumSuc]; ListaPredID = new int[NumTareas+1]; String inString = inbr.readLine(); StringTokenizer st = new StringTokenizer(inString); int a = Integer.valueOf(st.nextToken().trim()).intValue(); int b = Integer.valueOf(st.nextToken().trim()).intValue(); int aux; int cont=0; while(a != -1){ ListaSucID[a][cont]=b; ListaPredID[b]++; aux = a; inString = inbr.readLine(); st = new StringTokenizer(inString); a = Integer.valueOf(st.nextToken().trim()).intValue(); b = Integer.valueOf(st.nextToken().trim()).intValue(); if(a==aux) cont++; else cont=0; } } //Calcula el número máximo de sucesores de DI una vez rellenadas las //listas de sucesores y predecesores de ID. public int getNumSucDI() { int NumSucDI=0; for(int i=1; i<=NumTareas;i++){ if(ListaPredID[i]>NumSucDI) NumSucDI = ListaPredID[i]; } return (NumSucDI); } 35 //Crea y llena las listas de sucesores y predecesores de ID una vez //se tienen las de DI. public void llenaListaDI(int NumSucDI, int NumSucID) { ListaSucDI = new int[NumTareas+1][NumSucDI]; ListaPredDI = new int[NumTareas+1]; int cont[] = new int[NumTareas+1]; for(int i=0; i<=(NumSucDI-1);i++) cont[i]=0; for(int i=1;i<=NumTareas;i++){ for(int j=0;j<=(NumSucID-1);j++){ if(ListaSucID[i][j] != 0){ ListaSucDI[ListaSucID[i][j]][cont[ListaSucID[i][j]]]=i; ListaPredDI[i]++; cont[ListaSucID[i][j]]++; } } } } public static int getNumTareas() { return NumTareas; } public int sumaTiempos() { TiempoMax=0; int suma = 0; for(int i=1; i<=NumTareas; i++){ suma += Tiempos[i]; if (Tiempos[i]>TiempoMax) TiempoMax = Tiempos[i]; } return suma; } } 1.2.14 MatrizPesos public class MatrizPesos { static int MatrizID[][]; static int MatrizDI[][]; static int MatrizSuc[][]; final static void inicializa() { calculoMatrizSuc(); inicializaID(); inicializaDI(); 36 actualizaPesoAzar("ID"); actualizaPesoAzar("DI"); } final static void inicializaID() { //La matriz MatrizID contiene en la posicion [i][j] el peso //de la tarea j segun el criterio i segun el grafo directo MatrizID = new int[15][Datos.getNumTareas()+1]; peso1ID(); CotasTC cotas = new CotasTC(); //El cálculo de algunos pesos cotas.calculoCotasIniciales(); //requieren conocer la cotaMaxTC peso2ID(); peso3ID(); peso4ID(); peso5ID(); peso6ID(); peso7ID(); peso8ID(); peso9ID(); peso10ID(); peso11ID(); peso12ID(); peso13ID(); ConstruirMatrizPesos(MatrizID); } final static void inicializaDI() { //La matriz MatrizDI contiene en la posicion [i][j] el peso //de la tarea j segun el criterio i segun el grafo inverso MatrizDI = new int[15][Datos.getNumTareas()+1]; peso1DI(); peso2DI(); peso3DI(); peso4DI(); peso5DI(); peso6DI(); peso7DI(); peso8DI(); peso9DI(); peso10DI(); peso11DI(); peso12DI(); peso13DI(); ConstruirMatrizPesos(MatrizDI); } //Algoritmo de ordenacion rapida para estandarizar los pesos public static int[][] Quicksort (int a[][], int izq, int der) { int indiceTareaAux,indicePesoAux, i , j , k ; if(izq < der){ 37 i = izq; //Extremo izquierdo del vector o j = der; //extremo derecho del vector numero de componentes k = (int) ((izq+der)/2); //Punto que se utiliza como pivote en int pivote =a[k][1]; //la variable pivote se coloca el peso do { while((a[i][1] < pivote) ) i++; while((a[j][1] > pivote) ) j--; if (i <= j ){ indiceTareaAux =a[j][0]; indicePesoAux = a[j][1]; a[j][1] = a[i][1]; a[j][0] = a[i][0]; a[i][0] = indiceTareaAux; a[i][1] = indicePesoAux; i++; j--; } }while (i < j); a = Quicksort (a, izq, j); a = Quicksort (a, i, der); } return a; } //A este método se le pasa las tareas ordenadas convenientemente en //función de sus pesos, y los transforma a la forma estandar (todos //positivos y mayores que o)para el cálculo de los índices de decisión final static void ConstruirMatrizPesos(int MatrizPes[][]) { //Al método quicksort se le pasa la tarea y su peso //que se guarda en aux1[i][j], el índice de //la tarea se guarda en la columna i y el peso en la j int n=Datos.getNumTareas(); int [][] aux = new int [n+1][2]; for(int heuristica=1; heuristica <= 14 ; heuristica++){ for(int tarea=1 ; tarea <= n; tarea++) { aux[tarea][0] = tarea; aux[tarea][1] = MatrizPes[heuristica][tarea]; } //Se ordena el vector por pesos aux = Quicksort (aux, 1, n); //Se transforman los pesos MatrizPes[heuristica][aux[n][0]] = n; for(int i=n ; i>1; i--){ if(aux[i-1][1] == aux[i][1]) MatrizPes[heuristica][aux[i-1][0]] = MatrizPes[heuristica][aux[i][0]]; else if(aux[i-1][1] < aux[i][1]) MatrizPes[heuristica][aux[i-1][0]] = i-1; else System.out.println("error al calcular el peso "+ ": los pesos no se han ordenado bien"); } } } 38 public static void actualizaPesoAzar(String s) { int inferior, superior, aleatorio; int aux[]= new int[Datos.getNumTareas()]; //Se rellena el vector para despues extraer los numero de dicho // vector utilizando el azar no para obtener directamente el numero //sino a traves de los indices, los cuales se escogeran al azar inferior = 0; superior = Datos.getNumTareas(); for(int i=0; i<=Datos.getNumTareas()-1; i++) aux[i]=i+1; if (s.equals("ID")){ for(int i=1; i<=Datos.getNumTareas(); i++){ aleatorio=Azar.nextInt(inferior, superior-1); MatrizID[14][i] = aux[aleatorio]; aux[aleatorio]= aux[superior-1]; superior--; } } else if(s.equals("DI")){ for(int i=1; i<=Datos.getNumTareas(); i++){ aleatorio=Azar.nextInt(inferior, superior-1); MatrizDI[14][i] = aux[aleatorio]; aux[aleatorio]= aux[superior-1]; superior--; } MatrizDI[14][Datos.getNumTareas()] = aux[0]; } else System.out.println ("Error al leer parametro sentido en el fichero opciones"); } final static void calculoMatrizSuc() //Cálculo de la matriz de //sucesores totales { int MatrizSucAux[][]; int n=Datos.getNumTareas(); MatrizSuc = new int[n+1][n+1]; MatrizSucAux = new int[n+1][n+1]; int fila, columna, i, j, sumafila,aux,aux2; //Inicializar la matriz MatrizSuc con MatrizSucI for(fila=1 ;fila<=n ;fila++){ for(columna=1 ;columna<=n ;columna++) MatrizSuc[fila][columna]=Datos.MatrizSucI[fila][columna]; } //En la iteracion k se calcula el producto de la //matriz se sucesores MatrizSuc por ella misma sumafila=0; aux2=1; //Se ejecuta una nueva iteración si la suma de las diferencias 39 //entre los componentes de la iteración k i la k-1 (aux2) //es igual a cero while(aux2>0){ aux2=0; for(fila=1 ;fila<=Datos.getNumTareas() ;fila++){ for (columna=1 ;columna<=Datos.getNumTareas() ;columna++){ i=1; sumafila=0; while (i <= Datos.getNumTareas()){ aux=MatrizSuc[fila][i]*MatrizSuc[i][columna]; sumafila=sumafila+aux; i=i+1; } //Se cambian los componentes diferentes de 0 //por el valor 1 if(sumafila > 0) sumafila=1; if(sumafila < 0) System.out.println("error al calcular la matriz de sucesores totales"); //Se comprueba si algun componente de la matriz // MatrizSuc ha cambiado respecto a la //iteracion anterior aux2=aux2+Math.abs((sumafilaMatrizSuc[fila][columna])); MatrizSucAux[fila][columna]=sumafila; } } // copiar la matriz auxliar en la matriz MatrizSuc for(fila=1 ;fila<=Datos.getNumTareas() ;fila++){ for(columna=1 ;columna<=Datos.getNumTareas() ;columna++) MatrizSuc[fila][columna]=MatrizSucAux[fila][columna]; } } } // CONSTRUCCION DE LA MATRIZ DE PESOS ORIGINALES DE IZQUIERDA A DERECHA final static void peso1ID() { int n=Datos.getNumTareas(); for (int tarea=1; tarea<=n; tarea++) { MatrizID[1][tarea] = Datos.Tiempos[tarea]; } } final static void peso2ID(){ int n=Datos.getNumTareas(); for(int tarea=1; tarea<=n ; tarea++){ MatrizID[2][tarea] = Datos.ListaPredDI[tarea]; //El número de sucesores ID es el de predecesores DI } } final static void peso3ID(){ 40 int n=Datos.getNumTareas(); int peso3; for (int tarea=1; tarea<=n; tarea++) { peso3=0; for (int sucesor=1; sucesor<=n ; sucesor++) { if (MatrizSuc[tarea][sucesor] == 1) peso3=peso3+1; } MatrizID[3][tarea]=peso3-1; //la matriz de sucesores tambien incluye en la diagonal //el valor 1, por lo tanto hay que restarselo } } final static void peso4ID(){ int n=Datos.getNumTareas(); int peso4; for (int tarea=1; tarea<=n ; tarea++) { peso4=0; for (int sucesor=1; sucesor<=n ; sucesor++) { if (MatrizSuc[tarea][sucesor] == 1) peso4=peso4+Datos.Tiempos[sucesor]; } MatrizID[4][tarea]=peso4; } } final static void peso5ID(){ int n=Datos.getNumTareas(); int tarea=1; try { for(tarea=1; tarea<=n; tarea++) MatrizID[5][tarea]=(100*(MatrizID[4][tarea])/ ((MatrizID[3][tarea])+1)); } catch (ArithmeticException e){ System.out.println(tarea+" peso 5"); } } final static void peso6ID(){ int n=Datos.getNumTareas(); int tarea=1; try { for (tarea=1; tarea<=n ; tarea++) { MatrizID[6][tarea]= (int)Math.ceil(((double)(MatrizID[4][tarea])/ (double)(CotasTC.CotaMaxTC)))-n-1; } } catch (ArithmeticException e){ System.out.println(tarea+" peso 6"); } } final static void peso7ID(){ int n=Datos.getNumTareas(); int tarea=1; try { 41 for (tarea=1; tarea<=n ; tarea++) MatrizID[7][tarea]=(100*(MatrizID[6][tarea]))/ (MatrizID[3][tarea]+1); } catch (ArithmeticException e){ System.out.println(tarea+" peso 7"); } } final static void peso8ID(){ int n=Datos.getNumTareas(); int tarea=1; try { for (tarea=1; tarea<=n ; tarea++) MatrizID[8][tarea]=(1000*(MatrizID[1][tarea]))/ (-MatrizID[6][tarea]); } catch (ArithmeticException e){ System.out.println(tarea+" peso 8"); } } final static void peso9ID(){ int n=Datos.getNumTareas(); int tarea=1; int peso9, predecesor; try { for (tarea=1; tarea<=n ; tarea++) { peso9=0; for ( predecesor=1; predecesor<=n ; predecesor++) { if (MatrizSuc[predecesor][tarea] == 1) peso9=peso9+Datos.Tiempos[predecesor]; } MatrizID[9][tarea]=-(int)Math.ceil((double)peso9/ (double) CotasTC.CotaMaxTC); } } catch (ArithmeticException e){ System.out.println(tarea+" peso 9"); } } final static void peso10ID(){ int n=Datos.getNumTareas(); int tarea=1; try { for (tarea=1; tarea<=n ; tarea++) { MatrizID[10][tarea]=MatrizID[6][tarea]-MatrizID[9][tarea]; // +(-UB(i))-(-LB(i)) } } catch (ArithmeticException e){ System.out.println(tarea+" peso 10"); } } final static void peso11ID(){ int n=Datos.getNumTareas(); int tarea=1; 42 try { for (tarea=1; tarea<=n ; tarea++) { MatrizID[11][tarea]=(100*(MatrizID[3][tarea])/ (-MatrizID[10][tarea])); } } catch (ArithmeticException e){ System.out.println(tarea+" peso 11"); } } final static void peso12ID(){ int n=Datos.getNumTareas(); int tarea=1; try { for (tarea=1; tarea<=n ; tarea++) { MatrizID[12][tarea] = MatrizID[1][tarea] + MatrizID[3][tarea]; } } catch (ArithmeticException e){ System.out.println(tarea+" peso 12"); } } final static void peso13ID(){ int n=Datos.getNumTareas(); int i,tarea, predecesor, aux; //Se inicilizan los indices K&W los niveles se //establecen hacia atras, del final al principio for (i=1; i<=n ; i++) MatrizID[13][i]=1; aux=0; while (aux==0) { aux=1; //En este caso se empieza por la ultima tarea para disminuir //el numero de pasadas y asi aumentar la velocidad for (tarea=n; tarea>0 ; tarea--) { for( predecesor=1; predecesor<=n ; predecesor++) { //Para todas las tareas que tengan un predecesor inmediato if ((Datos.MatrizSucI[predecesor][tarea] == 1) && (tarea!=predecesor)){ //Como los niveles de calculan hacia atras, se //utiliza la matriz de predecesores si la tarea //tiene un predecesor inmediato con un nivel menor o //igual que dicha tarea, aumentar el nivel del //predecesor en 1 if(MatrizID[13][tarea]>=MatrizID[13][predecesor]){ MatrizID[13][predecesor]=MatrizID[13][tarea]+1; aux=0; } } } } } } 43 // CONSTRUCCION DE LA MATRIZ DE PESOS ORIGINALES DE DERECHA A IZQUIERDA final static void peso1DI(){ int n=Datos.getNumTareas(); for (int tarea=1; tarea<=n; tarea++) { MatrizDI[1][tarea]= Datos.Tiempos[tarea]; //La fila , el numero 1, representa el indice de peso } } final static void peso2DI(){ int n=Datos.getNumTareas(); for(int tarea=1; tarea<=n ; tarea++) MatrizDI[2][tarea] = Datos.ListaPredID[tarea]; } final static void peso3DI(){ int n=Datos.getNumTareas(); int peso3; for (int tarea=1; tarea<=n; tarea++) { peso3=0; for (int sucesor=1; sucesor<=n ; sucesor++) { if (MatrizSuc[sucesor][tarea] == 1) peso3=peso3+1; } MatrizDI[3][tarea]=peso3-1; //La matriz de sucesores tambien incluye en la diagonal //el valor 1, por lo tanto hay que restarselo } } final static void peso4DI(){ int n=Datos.getNumTareas(); int peso4; for (int tarea=1; tarea<=n ; tarea++) { peso4=0; for (int sucesor=1; sucesor<=n ; sucesor++) { if (MatrizSuc[sucesor][tarea] == 1) peso4=peso4+Datos.Tiempos[sucesor]; } MatrizDI[4][tarea]=peso4; } } final static void peso5DI(){ int n=Datos.getNumTareas(); int tarea=1; try { for(tarea=1; tarea<=n; tarea++) { MatrizDI[5][tarea]=(100*(MatrizDI[4][tarea])/ ((MatrizDI[3][tarea])+1)); } } catch (ArithmeticException e){ System.out.println(tarea+" peso 5 DI"); 44 } } final static void peso6DI(){ int n=Datos.getNumTareas(); int tarea=1; try { for (tarea=1; tarea<=n ; tarea++) { MatrizDI[6][tarea]= (int)Math.ceil(((double)(MatrizDI[4][tarea])/ (double)(CotasTC.CotaMaxTC)))-n-1; //se ha de calcular en algun sitio una cota maxima //del tiempo de ciclo } } catch (ArithmeticException e){ System.out.println(tarea+" peso 6 DI"); } } final static void peso7DI(){ int n=Datos.getNumTareas(); int tarea=1; try { for (tarea=1; tarea<=n ; tarea++) { MatrizDI[7][tarea]=(100*(MatrizDI[6][tarea]))/ (MatrizDI[3][tarea]+1); } } catch (ArithmeticException e){ System.out.println(tarea+" peso 7 DI"); } } final static void peso8DI(){ int n=Datos.getNumTareas(); int tarea=1; try { for (tarea=1; tarea<=n ; tarea++) { MatrizDI[8][tarea]= (1000*(MatrizDI[1][tarea]))/(-MatrizDI[6][tarea]); } } catch (ArithmeticException e){ System.out.println(tarea+" peso 8 DI"); } } final static void peso9DI(){ int n=Datos.getNumTareas(); int tarea=1; int peso9, predecesor; try { for (tarea=1; tarea<=n ; tarea++) { peso9=0; for ( predecesor=1; predecesor<=n ; predecesor++) { if (MatrizSuc[tarea][predecesor] == 1) peso9=peso9+Datos.Tiempos[predecesor]; } 45 MatrizDI[9][tarea]= -(int)Math.ceil((double)peso9/(double)CotasTC.CotaMaxTC); } } catch (ArithmeticException e){ System.out.println(tarea+" peso 9 } DI"); } final static void peso10DI(){ int n=Datos.getNumTareas(); int tarea=1; try { for (tarea=1; tarea<=n ; tarea++) { MatrizDI[10][tarea]=MatrizDI[6][tarea]-MatrizDI[9][tarea]; // +(-UB(i))-(-LB(i)) } } catch (ArithmeticException e){ System.out.println(tarea+" peso 10 DI"); } } final static void peso11DI(){ int n=Datos.getNumTareas(); int tarea=1; try { for (tarea=1; tarea<=n ; tarea++) { MatrizDI[11][tarea]=(100*(MatrizDI[3][tarea])/ (-MatrizDI[10][tarea])); } } catch (ArithmeticException e){ System.out.println(tarea+" peso 11"); } } final static void peso12DI(){ int n=Datos.getNumTareas(); int tarea=1; try { for (tarea=1; tarea<=n ; tarea++) { MatrizDI[12][tarea] = MatrizDI[1][tarea] + MatrizDI[3][tarea]; } } catch (ArithmeticException e){ System.out.println(tarea+" peso 12"); } } final static void peso13DI(){ int n=Datos.getNumTareas(); int i,tarea, predecesor, aux; //Inicializamos los indices K&W los niveles se establecen //hacia atras, del final al principio for (i=1; i<=n ; i++) MatrizDI[13][i]=1; aux=0; 46 while (aux==0) { aux=1; //En este caso se empieza por la ultima tarea para disminuir //el numero de pasadas y asi aumentar la velocidad for (tarea=1 ; tarea <= n ; tarea++) { for( predecesor=1; predecesor<=n ; predecesor++) { if ((Datos.MatrizSucI[tarea][predecesor] == 1) && (tarea != predecesor) ){ if(MatrizDI[13][tarea]>=MatrizDI[13][predecesor]){ MatrizDI[13][predecesor]=MatrizDI[13][tarea]+1; aux=0; } } } } } } public static void actualizaPesos() { peso6ID(); peso7ID(); peso8ID(); peso9ID(); peso10ID(); peso11ID(); peso6DI(); peso7DI(); peso8DI(); peso9DI(); peso10DI(); peso11DI(); } } 1.2.15 CotasTC public class CotasTC { static int CotaMinTC; static int CotaMaxTC; public CotasTC(){ CotaMaxTC = Datos.TiempoTotal; } public void calculoCotasIniciales() { CotaMinTC = calculoMinTC(); calculoMaxTC(); } public int calculoMinTC() { int tiempoMax = Datos.Tiempos[1]; 47 int sumaTiempos = tiempoMax; for(int i=2; i<=Datos.NumTareas ; i++){ sumaTiempos += Datos.Tiempos[i]; if(Datos.Tiempos[i]>tiempoMax) tiempoMax = Datos.Tiempos[i]; } if(tiempoMax <= (sumaTiempos/Datos.NumEstMax)) return (sumaTiempos/Datos.NumEstMax); else return tiempoMax; } public void calculoMaxTC() { int tareapos[] = new int[2]; Ristra ristra = new Ristra("ID"); NextTareaInicial next = new NextTareaInicial("ID"); for(int i=1; i<=Datos.NumTareas; i++){ tareapos = next.getTarea(1, ristra.ultimaT); ristra.actualizaRistraT(tareapos[0]); next.lista.actualizaListas(tareapos); } int Ristra[] = new int[Datos.NumTareas+1]; Ristra = ristra.getRistraT(); int TC2 = CotaMinTC; int tacum, tasig, TCajust2, n2, TCnext; int i, r; int marca, cota2; do{ //loop de tiempos de ciclo tacum = 0; tasig = 0; TCajust2 = 0; n2 = 1; r = 1; marca = 0; cota2 = 1; TCnext = 1000000000; do{ //loop de r i = Ristra[r]; tacum += Datos.Tiempos[i]; if(tacum > TC2){ if((tacum-Datos.Tiempos[i]) > TCajust2) TCajust2 = tacum-Datos.Tiempos[i]; if(tacum < TCnext) TCnext = tacum; tasig = tasig + tacum - Datos.Tiempos[i]; tacum = Datos.Tiempos[i]; n2 += 1; if((n2-1+(int)Math.floor((double)(Datos.TiempoTotaltasig)/TC2)) > Datos.NumEstMin) cota2 = 0; } if(r==Datos.NumTareas) 48 marca = 1; r++; } while((r<=Datos.NumTareas) && (n2<=Datos.NumEstMin) && (cota2>0)); if(tacum>TCajust2) {TCajust2 = tacum;} if(TC2 == Datos.TiempoTotal) {TCajust2 = TC2;} if(n2 > Datos.NumEstMin){ TC2 = TCnext; } else if(n2 == Datos.NumEstMin){ if(marca == 1){ if(TCajust2<CotaMaxTC) CotaMaxTC = TCajust2; TC2 = Datos.TiempoTotal+1; } else if(marca == 0){ if((Datos.TiempoTotal-tasig)<=TC2){ if((Datos.TiempoTotal-tasig)>TCajust2) TCajust2 = Datos.TiempoTotal-tasig; if(TCajust2<CotasTC.CotaMaxTC) CotaMaxTC = TCajust2; TC2 = Datos.TiempoTotal+1; } else if((Datos.TiempoTotal-tasig)>TC2) TC2 = TCnext; } } else if(n2<Datos.NumEstMin){ if(marca == 1){ TC2 = Datos.TiempoTotal+1; CotaMaxTC = TCajust2; } else if(marca == 0){ if((n2-1+(int)Math.floor((double)(Datos.TiempoTotaltasig)/TC2)) > Datos.NumEstMin) TC2 = TCnext; else if((n2-1+(int)Math.floor( (double)(Datos.TiempoTotal-tasig)/TC2)) <= Datos.NumEstMin) { TC2 = Datos.TiempoTotal+1; CotaMaxTC = Datos.TiempoTotal; } } } } while(TC2 <= Datos.TiempoTotal); } } 1.2.16 CotaSALBPE public class CotaSalbpE { int Cota1; int Cota2; int Cota3; 49 int Cota4; int [] TCicloMin; //En este vector se guarda para cada numero de //estaciones(SALBP-2)su cota minima de tiempo de //ciclo necesaria para empezar en el mayor //tiempo de ciclo posible la cota 4 static int CotaSalbpE; public CotaSalbpE() { TCicloMin = new int [Datos.NumEstMax-Datos.NumEstMin+1]; CalculoCota1(); System.out.println("cota1 : "+Cota1); CalculoCota2(); System.out.println("cota2 : "+Cota2); CalculoCota3(); System.out.println("cota3 : "+Cota3); CalculoCota4(); System.out.println("cota4 : "+Cota4); CotaSalbpE = maximo(Cota1, Cota2, Cota3, Cota4); System.out.println("CotaSalbpE : "+ CotaSalbpE); } public void CalculoCota1() { Cota1 = Datos.TiempoTotal; int aux; for (int i=0; i <= (Datos.NumEstMax-Datos.NumEstMin); i++){ aux=Datos.TiempoTotal/(Datos.NumEstMin+i); if (aux >= Datos.TiempoMax) TCicloMin[i] = aux; else TCicloMin[i] = Datos.TiempoMax; } } public void CalculoCota2() { Cota2 = Datos.TiempoMax * Datos.NumEstMin; } public void CalculoCota3() { int Cota3Aux,k, suma, sumaAux, estaciones; int n = Datos.getNumTareas(); int [][] auxTiempos = new int [n+1][2]; int [][] auxTiempos2 = new int [n+1][2]; //Se copian los tiempos en en vector auxTiempos ordenados de menor //a mayor y comenzando por la posicion for (int j=1 ; j <= n; j++){ auxTiempos[j][0]= j; auxTiempos[j][1]= Datos.Tiempos[j]; } //Se ordena el vector por pesos auxTiempos = MatrizPesos.Quicksort(auxTiempos, 0, n-1); //Se invierte el orden para que la tareas esten en orden //decreciente de tiempos 50 for (int t=1 ; t <= n; t++){ auxTiempos2[t][0] = auxTiempos[n-t+1][0]; auxTiempos2[t][1] = auxTiempos[n-t+1][1]; } Cota3=1000000000; for (estaciones = Datos.NumEstMin; estaciones <= Datos.NumEstMax; estaciones++){ k=1; suma = 0; while ( k <= (int) (Math.floor((double)((n-1)/estaciones)))){ //Ver sumatorio libro Scholl pag 56 sumaAux=0; for (int i = 0; i<=k; i++) sumaAux = sumaAux + auxTiempos2[(k*estaciones+1-i)][1]; if (sumaAux > suma) suma = sumaAux; k++; } if ( suma*estaciones < Cota3) Cota3 = suma*estaciones; if (suma > TCicloMin[estaciones-Datos.NumEstMin]) TCicloMin[estaciones-Datos.NumEstMin] = suma; } } public void CalculoCota4() { int estaciones; int tiempoCiclo; int tiempoAcum; int tarea; boolean finTareas = false; boolean finTiempoCiclo = false; int [] tiempoPredecesores = new int[Datos.NumTareas+1]; int [] EarliestStation = new int[Datos.NumTareas+1]; int [] LatestStation = new int[Datos.NumTareas+1]; //Se calcula el numerador de la formula de la EarliestStation //ya que es fijo para todos los tiempos de ciclo for (tarea=1; tarea <= Datos.NumTareas; tarea++) { tiempoAcum=0; for (int predecesor=1;predecesor<=Datos.NumTareas ;predecesor++){ if (MatrizPesos.MatrizSuc[predecesor][tarea] == 1) tiempoAcum=tiempoAcum+Datos.Tiempos[predecesor]; } tiempoPredecesores[tarea] = tiempoAcum; } Cota4=1000000000; for (estaciones = Datos.NumEstMin; estaciones <= Datos.NumEstMax; estaciones++){ //Se inicializa el tiempo de ciclo tiempoCiclo = TCicloMin[estaciones-Datos.NumEstMin]; 51 //Se calcula la EarliestStation y la LatestStation //para cada tarea while (tarea <= Datos.NumTareas){ EarliestStation[tarea] =(int)Math.ceil((double) tiempoPredecesores[tarea]/ (double) tiempoCiclo); LatestStation[tarea] = Datos.NumTareas+1(int)Math.ceil( ((double)(MatrizPesos.MatrizID[4][tarea])/ (double)(tiempoCiclo))); if (EarliestStation[tarea] > LatestStation[tarea]){ tiempoCiclo = tiempoCiclo+1; tarea = 1; } else tarea=tarea+1; } if ( tiempoCiclo*estaciones < Cota4) Cota4 = tiempoCiclo*estaciones; } } public int maximo(int cota1,int cota2, int cota3, int cota4) { int maximo; maximo = Math.max(cota1, cota2); maximo = Math.max(maximo, cota3); maximo = Math.max(maximo, cota4); return maximo; } } 1.2.17 Azar import java.util.*; public class Azar extends Random { static Random aleatorio; public static void semilla() { aleatorio = new Random(); } public static int nextInt (int inferior, int superior) { if (superior <= inferior-1) System.out.println("error al utilizar el metodo nextInt de la clase Azar: inferior > que superior"); int i; i = aleatorio.nextInt(); i = inferior + (Math.abs(i)) % (superior- inferior +1); return i; } } 52 1.2.18 MejorSolucion public class MejorSolucion { static int OBJ; static int N; static int TC; static int Ristra[]; static String sentidoHormiga; static String sentidoEval; static int OBJInicial; public static void inicializa() { OBJ = 1000000000; N = 1000000000; TC = 1000000000; Ristra = new int[Datos.NumTareas+1]; } } 1.2.19 Cronometro import java.util.*; public class Cronometro { Calendar i, f; int ihoras, iminutos, isegundos; int fhoras, fminutos, fsegundos; public Cronometro() { } public void inicio() { i = Calendar.getInstance(); ihoras = i.get(Calendar.HOUR_OF_DAY); iminutos = i.get(Calendar.MINUTE); isegundos = i.get(Calendar.SECOND); } public void fin() { f = Calendar.getInstance(); fhoras = f.get(Calendar.HOUR_OF_DAY); fminutos = f.get(Calendar.MINUTE); fsegundos = f.get(Calendar.SECOND); } 53 public int tiempo() //Devuelve el tiempo en segundos { int tiempo = -1; if(f.get(Calendar.DAY_OF_YEAR) == i.get(Calendar.DAY_OF_YEAR)){ tiempo = (fhoras - ihoras)*3600 + (fminutos - iminutos)*60 + (fsegundos - isegundos); } else if((f.get(Calendar.DAY_OF_YEAR) – i.get(Calendar.DAY_OF_YEAR)) == 1){ tiempo = (fhoras + (24-ihoras))*3600 + (fminutos - iminutos) *60 + (fsegundos - isegundos); } return tiempo; } } 1.2.20 Salida import import import import java.io.*; java.math.*; java.util.*; java.text.*; public class Salida { String Fichero; PrintWriter outbr, tablabr, distrbr; static int numSol; //Número de soluciones evaluadas int OBJInicial; public Salida(String f) { try{ //Fichero de salida con la evolución del porblema outbr = new PrintWriter(new FileWriter( "Evol_"+f+"-"+Datos.NumEstMin+""+Datos.NumEstMax+".dat", true)); //Tabla de resultados tablabr = new PrintWriter(new FileWriter( "Tabla_"+f+"-"+Datos.NumEstMin+""+Datos.NumEstMax+".dat", true)); //Distribución de tareas: solución final encontrada distrbr = new PrintWriter(new FileWriter( "Distr_"+f+"-"+Datos.NumEstMin+""+Datos.NumEstMax+".dat", true)); numSol = 0; } catch(FileNotFoundException e) { System.out.println("File Not Found"); 54 } catch(IOException e){ System.out.println("IO Exception"); } } public void acumulaSalida(Subcolonia sub) { outbr.print(MejorSolucion.OBJ+"\t"); int mejorSub = sub.PaqueteOBJ[0]; for(int ant=1; ant<=13; ant++){ if(sub.PaqueteOBJ[ant] < mejorSub) mejorSub = sub.PaqueteOBJ[ant]; } outbr.print(mejorSub+"\t"); double desviacion=0.0, media=0.0; for(int ant=0; ant<=13; ant++) media += (double)sub.PaqueteOBJ[ant]; media = media/14; for(int ant=0; ant<=13; ant++) desviacion += Math.pow((double)sub.PaqueteOBJ[ant]-media,2.0); desviacion = Math.pow(desviacion/13, 0.5); outbr.println(desviacion); } public void tablaSalida(int numSubColonia, int tiempo) { NumberFormat N = NumberFormat.getInstance(); N.setMinimumFractionDigits(3); N.setMaximumFractionDigits(3); tablabr.print(Datos.OBJOptima+"$"); //OBJ óptima del juego de datos tablabr.print(OBJInicial+"$"); tablabr.print(MejorSolucion.OBJ+"$"); tablabr.print(MejorSolucion.N+"$"); tablabr.print(MejorSolucion.TC+"$"); double discrepancia; discrepancia = (((double)(MejorSolucion.OBJ – Datos.OBJOptima))/(double)(Datos.OBJOptima))*100.0; tablabr.print(N.format(discrepancia)+"$"); //Discrepancia relativa a la solución óptima double mejora; mejora = (((double)(OBJInicial – MejorSolucion.OBJ))/(double)(OBJInicial))*100.0; tablabr.print(N.format(mejora)+"$"); tablabr.print(numSubColonia+"$"); tablabr.print(numSol+"$"); if(tiempo == 0) tablabr.println("1"); 55 if(tiempo != 0) tablabr.println(tiempo); } public void rellenaBlancos(int ultima) { for(int i=(ultima+1); i<=Opciones.limitacion; i++) outbr.println(); } public void estacionesSalida() { if(MejorSolucion.sentidoHormiga.equals("DI")) invertirRistra(); if(MejorSolucion.sentidoEval.equals(MejorSolucion.sentidoHormiga)) evaluacionNormal(); else evaluacionMarcas(); } public void invertirRistra() { int aux; for(int r=1; r<=(Datos.NumTareas/2); r++){ aux = MejorSolucion.Ristra[r]; MejorSolucion.Ristra[r] = MejorSolucion.Ristra[Datos.NumTareas-r+1]; MejorSolucion.Ristra[Datos.NumTareas-r+1] = aux; } } public void evaluacionNormal() { int n = 1; int tacum = 0; int cont = 0; int tmuerto[] = new int[MejorSolucion.N+1]; distrbr.println("@inicio"); for(int r=1; r<=Datos.NumTareas; r++){ tacum += Datos.Tiempos[MejorSolucion.Ristra[r]]; if(tacum > MejorSolucion.TC){ tmuerto[n] = MejorSolucion.TC -tacum + Datos.Tiempos[MejorSolucion.Ristra[r]]; tacum = Datos.Tiempos[MejorSolucion.Ristra[r]]; n++; } } 56 tmuerto[n] = MejorSolucion.TC - tacum; n=1; distrbr.println("Estacion 1 (Tiempo muerto= "+tmuerto[1]+")"); tacum = 0; for(int r=1; r<=Datos.NumTareas; r++){ tacum += Datos.Tiempos[MejorSolucion.Ristra[r]]; if(tacum > MejorSolucion.TC){ tacum = Datos.Tiempos[MejorSolucion.Ristra[r]]; n++; distrbr.println(); distrbr.println(); distrbr.println("Estacion "+n+ " (Tiempo muerto= "+tmuerto[n]+")"); cont = 0; } distrbr.print("\t"+MejorSolucion.Ristra[r]); cont++; if((cont == 10) && r<Datos.NumTareas){ if(tacum+Datos.Tiempos[MejorSolucion.Ristra[r+1]] <= MejorSolucion.TC){ cont = 0; distrbr.println(); } } } distrbr.println(); } public void evaluacionMarcas() { int marcas[] = new int[MejorSolucion.N+1]; //marcas[n] es la posicion donde acaba la estacion n int n = MejorSolucion.N; int tacum = 0; int cont = 0; int tmuerto[] = new int[MejorSolucion.N+1]; distrbr.println("@inicio"); for(int r=Datos.NumTareas; r>=1; r--){ tacum += Datos.Tiempos[MejorSolucion.Ristra[r]]; if(tacum > MejorSolucion.TC){ tmuerto[n] = MejorSolucion.TC -tacum + Datos.Tiempos[MejorSolucion.Ristra[r]]; tacum = Datos.Tiempos[MejorSolucion.Ristra[r]]; marcas[n-1] = r; n--; } } tmuerto[n] = MejorSolucion.TC - tacum; marcas[0] = 0; marcas[MejorSolucion.N] = Datos.NumTareas; 57 for(n=1; n<=MejorSolucion.N; n++){ cont = 0; distrbr.println(); distrbr.println("Estacion "+n+ " (Tiempo muerto= "+tmuerto[n]+")"); for(int r=marcas[n-1]+1; r<=marcas[n]; r++){ distrbr.print("\t"+MejorSolucion.Ristra[r]); cont++; if((cont == 10) && r != marcas[n]){ cont = 0; distrbr.println(); } } distrbr.println(); } } public void escribeSalida() { outbr.close(); tablabr.close(); distrbr.close(); } } 58 CAPÍTULO 2: ALGORITMO DE LAS HORMIGAS CON MEJORA LOCAL 59 2.1 DESCRIPCIÓN DEL PROGRAMA Utiliza todas las clases del programa del apartado 1, añadiendo la clase MejoraLocal y reemplazando la clase Subcolonia para que sea capaz de llamar a la clase MejoraLocal cuando sea necesario. 60 2.2 LISTADO DE LOS OBJETOS 2.2.1 MejoraLocal public class MejoraLocal { Ristra ristra; int numRistras; int r; static int mejorOBJ; int mejorTC; int mejorN; String sentido; String mejorSentidoEval; public MejoraLocal(Ristra ris, String s, int obj) { ristra = ris; r=0; mejorOBJ = obj; sentido = s; } public void inicia(int numRistras, String sentidoMejora) { if(sentidoMejora.equals("DI")){ invierte(); if(sentido.equals("ID")) sentido = "DI"; else sentido = "ID"; } for(int cont=1; cont<=numRistras; cont++){ intercambia(); compara(sentidoMejora); } if(sentidoMejora.equals("DI")) invierte(); } public void intercambia() { int aux; do{ if(r==Datos.NumTareas-1) r=0; r++; } while(factibilidad() == false); aux = ristra.RistraT[r]; ristra.RistraT[r] = ristra.RistraT[r+1]; ristra.RistraT[r+1] = aux; } 61 public boolean factibilidad() { //Factible si r+1 no es sucesor de r if((sentido.equals("ID")) && (MatrizPesos.MatrizSuc[ristra.RistraT[r]][ristra.RistraT[r+1]] == 1)) return false; else if((sentido.equals("DI")) && (MatrizPesos.MatrizSuc[ristra.RistraT[r+1]][ristra.RistraT[r]] == 1)) return false; else return true; } public void compara(String sentidoMejora) { ristra.evaluacionRistra(); int aux; if(ristra.eval.getObj() > mejorOBJ){ aux = ristra.RistraT[r]; ristra.RistraT[r] = ristra.RistraT[r+1]; ristra.RistraT[r+1] = aux; } if(ristra.eval.getObj() < mejorOBJ){ mejorOBJ = ristra.eval.getObj(); mejorN = ristra.eval.getNumEst(); mejorTC = ristra.eval.getTC(); if(sentidoMejora.equals("ID")) mejorSentidoEval = ristra.eval.mejorSentido; else { if(ristra.eval.mejorSentido.equals("ID")) mejorSentidoEval = "DI"; else mejorSentidoEval = "ID"; } } } public void invierte() { int aux; for(int r=1; r<=(Datos.NumTareas/2); r++){ aux = ristra.RistraT[r]; ristra.RistraT[r] = ristra.RistraT[Datos.NumTareas-r+1]; ristra.RistraT[Datos.NumTareas-r+1] = aux; } } } 62 2.2.2 Subcolonia public class Subcolonia { int tamano; //1 ó 14 String Sentido; Hormiga ant; int numAnt = 0; double b; boolean marcaMejor = false; //true si la mejor hormiga mejora //o iguala la OBJ global boolean marcaMejorSolo = false; //true si la mejor hormiga mejora //la OBJ global boolean mejorado, igualado; static int mejorsubOBJ; static int maxsubTC; MejoraLocal mejora; static int numSubcolonia; static int numMejora; //nº de mejora global boolean aplicaMejora; //true si se debe aplicar una mejora local static int numSubMejora; //nº mejora dentro de la subcolonia boolean lasPrimeras10; //Controla la mejora en las 10 primeras //subcolonias de hormigas //Atributos para la recolección de información int PaqueteRistras[][]; int PaqueteOBJ[]; int PaqueteN[]; int PaqueteTC[]; int auxRistra[]; int auxOBJ; int numSub; public Subcolonia(int t, String s, int n) { tamano = t; Sentido = s; PaqueteOBJ = new int[14]; PaqueteRistras = new int[14][Datos.NumTareas+1]; PaqueteN = new int[14]; PaqueteTC = new int[14]; MatrizPesos.actualizaPesoAzar(Sentido); mejorsubOBJ = 2000000000; maxsubTC = Datos.TiempoTotal; rastretes = Rastros.Tareas; numSub = n; igualado = false; mejorado = false; aplicaMejora = false; lasPrimeras10 = true; 63 } public void lanzaHormigas() { for(int i=1; i<=14; i++){ ant = new Hormiga(i, Sentido, Opciones.tipoHormiga); ant.construirSolucion(); recogeInformacion(); comparaInformacion(); numAnt++; } numSubcolonia++; if(aplicaMejora == true) numSubMejora++; } public void recogeInformacion() { for(int i=1; i<=Datos.NumTareas; i++) PaqueteRistras[numAnt][i] = ant.ristra.RistraT[i]; PaqueteOBJ[numAnt] = ant.ristra.eval.getObj(); PaqueteN[numAnt] = ant.ristra.eval.getNumEst(); PaqueteTC[numAnt] = ant.ristra.eval.getTC(); } public void comparaInformacion() { if((numSubcolonia <=10 || (numSubcolonia%30 == 0)) && lasPrimeras10 == true){ mejoraLocal("ID"); lasPrimeras10 = false; } if(PaqueteOBJ[numAnt] < MejorSolucion.OBJ){ MejorSolucion.OBJ = PaqueteOBJ[numAnt]; MejorSolucion.N = PaqueteN[numAnt]; MejorSolucion.TC = PaqueteTC[numAnt]; for(int i=1; i<=Datos.NumTareas; i++) MejorSolucion.Ristra[i] = PaqueteRistras[numAnt][i]; MejorSolucion.sentidoHormiga = Sentido; MejorSolucion.sentidoEval = ant.ristra.eval.mejorSentido; marcaMejorSolo = true; mejorado = true; } if(PaqueteOBJ[numAnt] <= MejorSolucion.OBJ){ marcaMejor = true; igualado = true; if((numMejora%2) != 0) mejoraLocal("ID"); else mejoraLocal("DI"); numMejora++; 64 aplicaMejora = true; } if(PaqueteOBJ[numAnt] < MejorSolucion.OBJ){ MejorSolucion.OBJ = PaqueteOBJ[numAnt]; MejorSolucion.N = PaqueteN[numAnt]; MejorSolucion.TC = PaqueteTC[numAnt]; for(int i=1; i<=Datos.NumTareas; i++) MejorSolucion.Ristra[i] = PaqueteRistras[numAnt][i]; MejorSolucion.sentidoEval = mejora.mejorSentidoEval; marcaMejorSolo = true; mejorado = true; } } public void actualizaRastros() { evaporaRastros(); actualizaTareas(); } public void actualizaTareas() { double unidadRastro[] = new double[15]; double sumaOBJ = 0; int tareaA, tareaB; if(tamano == 14){ //Dejan rastro todas las hormigas for(int i=0; i<=13; i++){ b = 100.0*(((double)(PaqueteOBJ[i])(double)(Datos.TiempoTotal))/ ((double)(Datos.TiempoTotal))); unidadRastro[i] = 1/(Math.pow(b, 1.0)); } for(int contAnt = 0; contAnt<=13; contAnt++){ tareaA = 0; for(int r=1; r<=Datos.NumTareas; r++){ //r = posición en la ristra tareaB = PaqueteRistras[contAnt][r]; Rastros.Tareas[tareaA][tareaB] += unidadRastro[contAnt]; tareaA = tareaB; } } } //Sólo dejan rastro las mejores hormigas int minOBJ[] = new int[14]; //Contiene las hormigas con mejor OBJ int limAnt = 0; minOBJ[0] = 0; for(int contAnt=1; contAnt<=13; contAnt++){ 65 if(PaqueteOBJ[contAnt]<PaqueteOBJ[minOBJ[0]]){ minOBJ[0] = contAnt; limAnt = 0; } else if(PaqueteOBJ[contAnt]==PaqueteOBJ[minOBJ[0]]){ minOBJ[limAnt+1] = contAnt; limAnt++; } } if(marcaMejor == true){ //La mejor hormiga mejora //o iguala la OBJ global for(int i=0; i<=limAnt; i++){ tareaA = 0; for(int r=1; r<=Datos.NumTareas; r++){ tareaB = PaqueteRistras[minOBJ[i]][r]; double maxRastro = 0.0; for(int j=0; j<=Datos.NumTareas; j++){ //Se busca el máximo rastro if(Rastros.Tareas[tareaA][j] > maxRastro) maxRastro = Rastros.Tareas[tareaA][j]; } //Evaporación extra if(marcaMejorSolo == true){ for(int j=0; j<=Datos.NumTareas; j++){ Rastros.Tareas[tareaA][j] *= (1-Opciones.evaporacionExtra); } maxRastro *= Opciones.rastroExtra; if(numSubcolonia == 1) maxRastro *=Opciones.tamano; } Rastros.Tareas[tareaA][tareaB] = maxRastro; tareaA = tareaB; } if(marcaMejorSolo == true){ double maxRastro = 0.0; for(int j=0; j<=Datos.NumTareas; j++){ //Se busca el máximo rastro if(Rastros.Tareas[tareaA][j] > maxRastro) maxRastro = Rastros.Tareas[tareaA][j]; } //Evaporación extra de la fila de la //última tarea de la ristra for(int pos=0; pos<=Datos.NumTareas; pos++){ Rastros.Tareas[tareaA][pos] *= (1-Opciones.evaporacionExtra); } maxRastro *= Opciones.rastroExtra; if(numSubcolonia == 1) maxRastro *=Opciones.tamano; Rastros.Tareas[tareaA][0] = maxRastro; marcaMejorSolo = false; //Ya no entra más, sólo evapora //la primera hormiga } } 66 } for(int i=0; i<=limAnt; i++){ b = 100.0*(((double)(PaqueteOBJ[minOBJ[i]])((double)(CotaSalbpE.CotaSalbpE)))/ ((double)(CotaSalbpE.CotaSalbpE))); double unidad = 1/(Math.pow(b, 2.0)); tareaA = 0; for(int r=1; r<=Datos.NumTareas; r++){ tareaB = PaqueteRistras[minOBJ[i]][r]; Rastros.Tareas[tareaA][tareaB] += unidad; tareaA = tareaB; } Rastros.Tareas[tareaA][0] += unidad; //Rastro entre la última //tarea de la ristra y la //tarea 0 en sentido //contrario } } public void evaporaRastros() { for(int i=0; i<=Datos.NumTareas; i++){ for(int j=0; j<=Datos.NumTareas; j++){ Rastros.Tareas[i][j] = Rastros.Tareas[i][j]* (1.0-Opciones.evaporacion); } } } public void mejoraLocal(String sentidoMejora) { if(numSubcolonia >= 0 && numSubMejora <=80){ Hormiga antMejora = new Hormiga(1, Sentido, Opciones.tipoHormiga); for(int i=1; i<=Datos.NumTareas; i++) antMejora.ristra.RistraT[i] = PaqueteRistras[numAnt][i]; mejora = new MejoraLocal(antMejora.ristra, Sentido, PaqueteOBJ[numAnt]); mejora.inicia(2000, sentidoMejora); if(mejora.mejorOBJ < PaqueteOBJ[numAnt]){ PaqueteOBJ[numAnt] = mejora.mejorOBJ; PaqueteN[numAnt] = mejora.mejorN; PaqueteTC[numAnt] = mejora.mejorTC; for(int i=1; i<=Datos.NumTareas; i++) PaqueteRistras[numAnt][i] = mejora.ristra.RistraT[i]; } 67 if(mejora.mejorOBJ < MejorSolucion.OBJ){ System.out.println(); System.out.println("Mejora con OBJ= "+ mejora.mejorOBJ+" con sentido "+numMejora); } } } } 68 CAPÍTULO 3: MULTI-START 69 3.1 DESCRIPCIÓN DEL PROGRAMA Se aprovechan objetos de los dos capítulos anteriores: • Azar • CotaSalbpE • CotaTC • Cronometro • Datos • Evaluación • Listas • MatrizPesos • MejoraLocal • MejorSolucion • NextTarea • Ristra • Salida Se reemplazan Principal y SolucionInicial para adaptarlos al funcionamiento del Multi-Start. 70 3.2 LISTADO DE OBJETOS 3.2.1 Principal public class Principal { public static void main(String args[]) { String sentido; int numRistras; int subNum; Cronometro cr = new Cronometro(); cr.inicio(); //Puesta a cero del cronómetro Azar.semilla(); Datos datos = new Datos(args); datos.importaDatos(); Salida salida = new Salida(args[6]); SolucionInicial solini; MatrizPesos.inicializa(); CotaSalbpE cota = new CotaSalbpE(); MejorSolucion.inicializa(); MejoraLocal mejora; numRistras = 0; cr.fin(); for(int numIni=1; !MejorSolucion.optimo && cr.tiempo()<=(Integer.valueOf(args[4].trim()).intValue()); numIni++){ if((numIni%2)!=0) sentido = "ID"; else sentido = "DI"; MatrizPesos.actualizaPesoAzar(sentido); solini = new SolucionInicial(sentido); solini.creaSolucion(14); mejora = new MejoraLocal(solini.ristra, sentido); int numRis=Integer.valueOf(args[5].trim()).intValue(); subNum = mejora.inicia(numRis); numRistras += subNum; cr.fin(); } System.out.println(); System.out.println(); System.out.println("MEJOR SOLUCION"); System.out.println("OBJ= "+MejorSolucion.OBJ); System.out.println("N = "+MejorSolucion.N); System.out.println("TC = "+MejorSolucion.TC); cr.fin(); System.out.println(); System.out.println("Tiempo de ejecucion: "+cr.tiempo()+" s"); 71 salida.tablaSalida(numRistras, cr.tiempo()); salida.estacionesSalida(); salida.escribeSalida(); } } 3.2.2 SolucionInicial public class SolucionInicial { String sentido; int tareapos[]; Ristra ristra; NextTarea next; public SolucionInicial(String sentido) { this.sentido = sentido; } public void creaSolucion(int h) { tareapos = new int[2]; ristra = new Ristra(sentido); next = new NextTarea(sentido); for(int i=1; i<=Datos.NumTareas; i++){ tareapos = next.getTarea(h, ristra.ultimaT); ristra.actualizaRistraT(tareapos[0]); next.lista.actualizaListas(tareapos); } } }