/*********************************************************************** This file is part of KEEL-software, the Data Mining tool for regression, classification, clustering, pattern mining and so on. Copyright (C) 2004-2010 F. Herrera (herrera@decsai.ugr.es) L. S�nchez (luciano@uniovi.es) J. Alcal�-Fdez (jalcala@decsai.ugr.es) S. Garc�a (sglopez@ujaen.es) A. Fern�ndez (alberto.fernandez@ujaen.es) J. Luengo (julianlm@decsai.ugr.es) This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see http://www.gnu.org/licenses/ **********************************************************************/ // // Cromosoma.java // // Salvador Garc�a L�pez // // Created by Salvador Garc�a L�pez 3-10-2005. // Copyright (c) 2004 __MyCompanyName__. All rights reserved. // package keel.Algorithms.Instance_Generation.SSMASFLSDE; import java.util.Arrays; import keel.Algorithms.Preprocess.Basic.*; import org.core.*; public class Cromosoma implements Comparable { /*Cromosome data structure*/ boolean cuerpo[]; /*Index for nearest neighbours*/ int vecinos[][]; /*Useful data for cromosomes*/ double fitness; double fitnessAc; boolean evaluado; boolean valido; /*Construct a random cromosome of specified size (OK)*/ public Cromosoma (int K, int size, double dMatrix[][], double datos[][], double real[][], int nominal[][], boolean nulo[][], boolean distanceEu) { double u; int i, j; cuerpo = new boolean[size]; vecinos = new int[size][K]; for (i=0; i<size; i++) { u = Randomize.Rand(); if (u < 0.5) { cuerpo[i] = false; } else { cuerpo[i] = true; } } evaluado = false; valido = true; for (i=0; i<size; i++) { for (j=0; j<K; j++) { vecinos[i][j] = obtenerCercano(vecinos[i],j,dMatrix, i, datos, real, nominal, nulo, distanceEu); } } } /*Create a copied cromosome*/ public Cromosoma (int K, int size, Cromosoma a) { int i, j; cuerpo = new boolean[size]; vecinos = new int[size][K]; for (i=0; i<cuerpo.length; i++) { cuerpo[i] = a.getGen(i); for (j=0; j<K; j++) { vecinos[i][j] = a.getVecino(i,j); } } fitness = a.getFitness(); fitnessAc = a.getFitnessAc(); evaluado = true; valido = true; } /*Construct a cromosome throught crossover than other two parents (OK)*/ public Cromosoma (int K, Cromosoma a, Cromosoma b, double pCross, int size) { int i; cuerpo = new boolean[size]; vecinos = new int[size][K]; for (i=0; i<cuerpo.length; i++) { if (Randomize.Rand() < pCross) { cuerpo[i] = b.getGen(i); } else { cuerpo[i] = a.getGen(i); } } evaluado = false; valido = true; } public void mutation (int K, double pMut, double dMatrix[][], double datos[][], double real[][], int nominal[][], boolean nulo[][], boolean distanceEu) { int i, j; for (i=0; i<cuerpo.length; i++) { if (Randomize.Rand() < pMut) { cuerpo[i] = !cuerpo[i]; } } for (i=0; i<cuerpo.length; i++) { for (j=0; j<K; j++) { vecinos[i][j] = obtenerCercano(vecinos[i],j,dMatrix, i, datos, real, nominal, nulo, distanceEu); } } } /*Obtain the nearest neighbour given a mask (cromosome)*/ public int obtenerCercano (int vecinos[], int J, double dMatrix[][], int index, double datos[][], double real[][], int nominal[][], boolean nulo[][], boolean distanceEu) { double minDist; int minPos, i, j; double dist; boolean perfect, cont; if (dMatrix == null) { perfect = false; i = 0; do { for ( ; i < cuerpo.length && !cuerpo[i]; i++); cont = true; for (j=0; j<J && cont; j++) { if (vecinos[j] == i) { cont = false; i++; } } perfect = cont; } while (!perfect); minPos = i; if (minPos == cuerpo.length) return 0; minDist = KNN.distancia(datos[index],real[index], nominal[index], nulo[index], datos[minPos], real[minPos], nominal[minPos], nulo[minPos], distanceEu); for (i=minPos+1; i<cuerpo.length; i++) { if (cuerpo[i]) { cont = true; for (j=0; j<J && cont; j++) { if (vecinos[j] == i) { cont = false; } } if (cont) { dist = KNN.distancia(datos[index],real[index], nominal[index], nulo[index], datos[i], real[i], nominal[i], nulo[i], distanceEu); if (minDist > dist) { minPos = i; minDist = dist; } } } } } else { perfect = false; i = 0; do { for (; i < cuerpo.length && !cuerpo[i]; i++); cont = true; for (j=0; j<J && cont; j++) { if (vecinos[j] == i) { cont = false; i++; } } perfect = cont; } while (!perfect); minPos = i; if (minPos == cuerpo.length) return 0; minDist = dMatrix[index][minPos]; for (i=minPos+1; i<cuerpo.length; i++) { if (cuerpo[i]) { cont = true; for (j=0; j<J && cont; j++) { if (vecinos[j] == i) { cont = false; } } if (cont) { if (minDist > dMatrix[index][i]) { minPos = i; minDist = dMatrix[index][i]; } } } } } return minPos; } public boolean getGen (int indice) { return cuerpo[indice]; } public int getVecino (int indicei, int indicej) { return vecinos[indicei][indicej]; } public double getFitness () { return fitness; } public double getFitnessAc () { return fitnessAc; } /*Function that evaluates a cromosome completely*/ public void evaluacionCompleta (int nClases, int K, int clases[]) { double contador = 0; int i, j; int votos[]; int maxPos=0, maxValue; votos = new int[nClases]; for (i=0; i<vecinos.length; i++) { Arrays.fill(votos,0); for (j=0; j<K; j++) { votos[clases[vecinos[i][j]]]++; } maxValue = votos[0]; maxPos = 0; for (j=1; j<nClases; j++) { if (votos[j] > maxValue) { maxValue = votos[j]; maxPos = j; } } if (clases[i] == maxPos) contador++; } fitness = contador*50.0/(double)cuerpo.length + (((double)cuerpo.length - (double)this.genesActivos())/(double)cuerpo.length)*50.0; fitnessAc = contador; evaluado = true; } public void borrar () { valido = false; } public boolean esValido () { return valido; } public void setGen (int pos, boolean valor) { cuerpo[pos] = valor; } public boolean estaEvaluado () { return evaluado; } public int genesActivos () { int i, suma = 0; for (i=0; i<cuerpo.length; i++) { if (cuerpo[i]) suma++; } return suma; } public double optimizacionLocal (int nClases, int K, int clases[], double dMatrix[][], double umbral, double datos[][], double real[][], int nominal[][], boolean nulo[][], boolean distanceEu) { int n, pos, i, j, k, tmp; double evaluaciones = 0; double ev; int visitas[]; n = this.genesActivos(); visitas = new int[n]; for (j=0, k=0; j<cuerpo.length; j++) { if (cuerpo[j]) { visitas[k] = j; k++; } } for (j=0; j<visitas.length; j++) { pos = Randomize.Randint (j, visitas.length-1); tmp = visitas[j]; visitas[j] = visitas[pos]; visitas[pos] = tmp; } i = 0; while (i < n) { ev = evaluacionParcial(nClases, K, clases, visitas[i], dMatrix, umbral, datos, real, nominal, nulo, distanceEu); if (ev >= 0) { n--; i = 0; visitas = new int[n]; try { for (j = 0, k = 0; j < cuerpo.length; j++) { if (cuerpo[j]) { visitas[k] = j; k++; } } } catch (Exception e) { i = n; } for (j=0; j<visitas.length; j++) { pos = Randomize.Randint (j, visitas.length-1); tmp = visitas[j]; visitas[j] = visitas[pos]; visitas[pos] = tmp; } } else { i++; } evaluaciones += Math.abs(ev); } return evaluaciones; } public double evaluacionParcial (int nClases, int K, int clases[], int ref, double dMatrix[][], double umbral, double datos[][], double real[][], int nominal[][], boolean nulo[][], boolean distanceEu) { int i, j; int vecinosTemp[][]; double ganancia = 0; //an instance just been dropped int contador = 0; int votos[]; int maxPosAnterior=0, maxPosNuevo = 0,maxValue; boolean evaluar; votos = new int[nClases]; vecinosTemp = new int[cuerpo.length][K]; cuerpo[ref] = false; for (i=0; i<cuerpo.length; i++) { evaluar = false; for (j=0; j<K; j++) { if (vecinos[i][j] == ref) { evaluar = true; vecinosTemp[i][j] = obtenerCercano(vecinosTemp[i],j,dMatrix, i, datos, real, nominal, nulo, distanceEu); } else { vecinosTemp[i][j] = vecinos[i][j]; } } if (evaluar) { contador++; Arrays.fill(votos, 0); for (j = 0; j < K; j++) { votos[clases[vecinos[i][j]]]++; } maxValue = votos[0]; maxPosAnterior = 0; for (j = 1; j < nClases; j++) { if (votos[j] > maxValue) { maxValue = votos[j]; maxPosAnterior = j; } } Arrays.fill(votos, 0); for (j = 0; j < K; j++) { votos[clases[vecinosTemp[i][j]]]++; } maxValue = votos[0]; maxPosNuevo = 0; for (j = 1; j < nClases; j++) { if (votos[j] > maxValue) { maxValue = votos[j]; maxPosNuevo = j; } } if (clases[i] == maxPosAnterior && clases[i] != maxPosNuevo) { ganancia--; } else if (clases[i] != maxPosAnterior && clases[i] == maxPosNuevo) { ganancia++; } } } if (Math.round(ganancia) >= (double)umbral) { for (i=0; i<cuerpo.length; i++) { for (j=0; j<K; j++) { vecinos[i][j] = vecinosTemp[i][j]; } } fitness += (ganancia*50.0/(double)cuerpo.length + (1.0/(double)cuerpo.length)*50.0); fitnessAc += ganancia; return ((double)contador)/((double)cuerpo.length); } else { cuerpo[ref] = true; return (((double)contador)/((double)cuerpo.length))*(-1); } } /*Function that lets compare cromosomes to sort easily*/ public int compareTo (Object o1) { double valor1 = this.fitness; double valor2 = ((Cromosoma)o1).fitness; if (valor1 > valor2) return -1; else if (valor1 < valor2) return 1; else return 0; } /*Function that inform about if a cromosome is different only in a bit, obtain the position of this bit. In case of have more differences, it returns -1*/ public int differenceAtOne (Cromosoma a) { int i; int cont = 0, pos = -1; for (i=0; i<cuerpo.length && cont < 2; i++) if (cuerpo[i] != a.getGen(i)) { pos = i; cont++; } if (cont >= 2) return -1; else return pos; } public String toString() { int i; String temp = "["; for (i=0; i<cuerpo.length; i++) if (cuerpo[i]) temp += "1"; else temp += "0"; temp += ", " + String.valueOf(fitness) + ", " + String.valueOf(genesActivos()) + "]"; return temp; } }