/***********************************************************************
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/
**********************************************************************/
package keel.Algorithms.Fuzzy_Rule_Learning.Genetic.ClassifierMOGUL;
/**
* <p>
* @author Written by Jesus Alcala Fernandez (University of Granada) 01/01/2004
* @author Modified by Francisco José Berlanga (University of Jaén) 09/12/2008
* @version 1.0
* @since JDK 1.6
* </p>
*/
import java.lang.Math;
import org.core.*;
class GA {
/**
* <p>
* This class implements a generational genetic algorithm
* </p>
*/
public double prob_cruce, prob_mutacion;
public int Mu_next, Trials;
public double Best_current_perf;
public int Best_guy, tipo_modificadores, n_etiquetas;
public int long_poblacion, n_genes, total_reglas;
public int[] sample;
public int last;
public Structure[] Old;
public Structure[] New;
public Structure[] temp;
public Adap_Sel fun_adap;
/**
* <p>
* Constructor
* </p>
* @param n_poblacion int The population size
* @param genes int The number of genes per individual in the population
* @param cruce double Crossover probability
* @param mutation double Mutation probability
* @param funcion Adap_Sel Adaptation function
* @param total_reg int Total number of rules
* @param tipo int Type of the lisguistic modifiers
* @param num_etiq int The number of linguistic labels per variable
* @param num_clases int The number of classes of the problem
*/
public GA(int n_poblacion, int genes, double cruce, double mutacion,
Adap_Sel funcion, int total_reg, int tipo, int num_etiq,
int num_clases) {
int i;
long_poblacion = n_poblacion;
n_genes = genes;
prob_cruce = cruce;
prob_mutacion = mutacion / (double) n_genes;
fun_adap = funcion;
total_reglas = total_reg;
tipo_modificadores = tipo;
n_etiquetas = num_etiq;
sample = new int[long_poblacion];
Old = new Structure[long_poblacion];
New = new Structure[long_poblacion];
for (i = 0; i < long_poblacion; i++) {
Old[i] = new Structure(n_genes, num_clases);
New[i] = new Structure(n_genes, num_clases);
}
}
private int ceil(double v) {
int valor;
valor = (int) Math.round(v);
if ((double) valor < v) {
valor++;
}
return (valor);
}
/**
* <p>
* It swaps the old and the new population
* </p>
*/
public void Swap() {
temp = Old;
Old = New;
New = temp;
}
/**
* <p>
* Inicialization of the population
* </p>
*/
public void Initialize() {
int i, j, aux;
last = (int) ((prob_cruce * long_poblacion) - 0.5);
Trials = 0;
if (prob_mutacion < 1.0) {
Mu_next = ceil(Math.log(Randomize.Rand()) /
Math.log(1.0 - prob_mutacion));
} else {
Mu_next = 1;
}
/* Generation of the initial population:
1.- 1 chromosome containing all the learned rules and without hedges.
2.- 10 chromosomes containing all the rules and with the hedges randomly selected.
3.- 1 chromosome containing all the rules and with all the hedges been "more or less".
4.- 1 chromosome containig all the rules and with all hedges been "very".
5.- The rest is randomly selected. */
/* Chromosome 0 */
for (j = 0; j < total_reglas; j++) {
New[0].GeneSel[j] = '1';
}
/* If n_genes_modificadores = 0 then n_genes=total_reglas
and the loop won't be executed */
for (j = total_reglas; j < n_genes; j++) {
New[0].GeneSel[j] = '0';
}
New[0].n_e = 1;
/* Chromosomes from 1 to 10 */
for (i = 1; i < 11; i++) {
for (j = 0; j < total_reglas; j++) {
New[i].GeneSel[j] = '1';
}
for (j = total_reglas; j < n_genes; j++) {
aux = Randomize.RandintClosed(0, 2);
switch (aux) {
case 0:
New[i].GeneSel[j] = '0';
break;
case 1:
New[i].GeneSel[j] = '1';
break;
case 2:
New[i].GeneSel[j] = '2';
}
}
New[i].n_e = 1;
}
/* Chromosome 11 */
for (j = 0; j < total_reglas; j++) {
New[11].GeneSel[j] = '1';
}
for (j = total_reglas; j < n_genes; j++) {
New[11].GeneSel[j] = '1';
}
New[11].n_e = 1;
/* Chromosome 12 */
for (j = 0; j < total_reglas; j++) {
New[12].GeneSel[j] = '1';
}
for (j = total_reglas; j < n_genes; j++) {
New[12].GeneSel[j] = '2';
}
New[12].n_e = 1;
/* Rest of the chomosomes */
for (i = 13; i < long_poblacion; i++) {
for (j = 0; j < total_reglas; j++) {
if (Randomize.RandintClosed(0, 1) == 0) {
New[i].GeneSel[j] = '0';
} else {
New[i].GeneSel[j] = '1';
}
}
for (j = total_reglas; j < n_genes; j++) {
aux = Randomize.RandintClosed(0, 2);
switch (aux) {
case 0:
New[i].GeneSel[j] = '0';
break;
case 1:
New[i].GeneSel[j] = '1';
break;
case 2:
New[i].GeneSel[j] = '2';
}
}
New[i].n_e = 1;
}
}
/**
* <p>
* Selection based on the Baker's Estocastic Universal Sampling
* </p>
*/
void Select() {
double expected, factor, perf, ptr, sum, rank_max, rank_min;
int i, j, k, best, temp;
rank_min = 0.75;
/* we assign the ranking to each element:
The best: ranking = long_poblacion-1
The worse: ranking = 0 */
for (i = 0; i < long_poblacion; i++) {
Old[i].n_e = 0;
}
/* we look for the best ordered non element */
for (i = 0; i < long_poblacion - 1; i++) {
best = -1;
perf = 0.0;
for (j = 0; j < long_poblacion; j++) {
if ((Old[j].n_e == 0) && (best == -1 || Old[j].Perf < perf)) {
perf = Old[j].Perf;
best = j;
}
}
/* we assign the ranking */
Old[best].n_e = long_poblacion - 1 - i;
}
/* we normalize the ranking */
rank_max = 2.0 - rank_min;
factor = (rank_max - rank_min) / (double) (long_poblacion - 1);
/* we assign the number of replicas of each chormosome according to the select probability */
k = 0;
ptr = Randomize.Rand();
for (sum = i = 0; i < long_poblacion; i++) {
expected = rank_min + Old[i].n_e * factor;
for (sum += expected; sum >= ptr; ptr++) {
sample[k++] = i;
}
}
/* we complete the population if necessary */
if (k != long_poblacion) {
for (; k < long_poblacion; k++) {
sample[k] = Randomize.RandintClosed(0, long_poblacion-1);
}
}
/* we shuffle the selected chromosomes */
for (i = 0; i < long_poblacion; i++) {
j = Randomize.RandintClosed(i, long_poblacion-1);
temp = sample[j];
sample[j] = sample[i];
sample[i] = temp;
}
/* we create the new population */
for (i = 0; i < long_poblacion; i++) {
k = sample[i];
for (j = 0; j < n_genes; j++) {
New[i].GeneSel[j] = Old[k].GeneSel[j];
}
New[i].Perf = Old[k].Perf;
New[i].n_e = 0;
}
}
/**
* <p>
* Crossover Operator
* </p>
*/
void Multipoint_Crossover() {
int mom, dad, xpoint1, xpoint2, i, j;
char temp;
for (mom = 0; mom < last; mom += 2) {
dad = mom + 1;
/* we generate the 2 crossing points */
xpoint1 = Randomize.RandintClosed(0, n_genes-1);
if (xpoint1 != n_genes - 1) {
xpoint2 = Randomize.RandintClosed(xpoint1 + 1, n_genes-1);
}
else {
xpoint2 = n_genes - 1;
}
/* we cross the individuals between xpoint1 and xpoint2 */
for (i = xpoint1; i <= xpoint2; i++) {
temp = New[mom].GeneSel[i];
New[mom].GeneSel[i] = New[dad].GeneSel[i];
New[dad].GeneSel[i] = temp;
}
New[mom].n_e = 1;
New[dad].n_e = 1;
}
}
/**
* <p>
* Uniform Mutation Operator
* </p>
*/
void Uniform_Mutation() {
int posiciones, i, j, aux;
double m;
char nuevo = ' ';
posiciones = n_genes * long_poblacion;
if (prob_mutacion > 0) {
while (Mu_next < posiciones) {
/* we determinate the chromosome and the gene */
i = Mu_next / n_genes;
j = Mu_next % n_genes;
/* we mutate the gene */
if (j < total_reglas) {
if (New[i].GeneSel[j] == '0') {
New[i].GeneSel[j] = '1';
} else {
New[i].GeneSel[j] = '0';
}
} else {
/* For the hedges, we generate a random value and choose one of the three options */
switch (tipo_modificadores) {
case 1:
case 2:
do {
aux = Randomize.RandintClosed(0, 2);
switch (aux) {
case 0:
nuevo = '0';
break;
case 1:
nuevo = '1';
break;
case 2:
nuevo = '2';
}
} while (nuevo == New[i].GeneSel[j]);
New[i].GeneSel[j] = nuevo;
}
}
New[i].n_e = 1;
/* we calculate the next position */
if (prob_mutacion < 1) {
m = Randomize.Rand();
Mu_next += ceil(Math.log(m) / Math.log(1.0 - prob_mutacion));
} else {
Mu_next += 1;
}
}
}
Mu_next -= posiciones;
}
/**
* <p>
* Fitness Function
* </p>
*/
void Evaluate() {
double performance;
int i, j;
for (i = 0; i < long_poblacion; i++) {
/* if the chromosome aren't evaluated, it's evaluate */
if (New[i].n_e == 1) {
New[i].Perf = fun_adap.eval(New[i].GeneSel);
performance = New[i].Perf;
New[i].n_e = 0;
Trials++;
/* we increment the number of evaluated chromosomes */
} else {
performance = New[i].Perf;
}
/* we calculate the position of the best individual */
if (i == 0) {
Best_current_perf = performance;
Best_guy = 0;
} else if (performance < Best_current_perf) {
Best_current_perf = performance;
Best_guy = i;
}
}
}
/**
* <p>
* Elitist selection
* </p>
*/
void Elitist() {
int i, k, found;
/* if the best individual of the old population aren't in the new population, we remplace the last individual for this */
for (i = 0, found = 0; i < long_poblacion && (found == 0); i++) {
for (k = 0, found = 1; (k < n_genes) && (found == 1); k++) {
if (New[i].GeneSel[k] != Old[Best_guy].GeneSel[k]) {
found = 0;
}
}
}
if (found == 0) {
for (k = 0; k < n_genes; k++) {
New[long_poblacion - 1].GeneSel[k] = Old[Best_guy].GeneSel[k];
}
New[long_poblacion - 1].Perf = Old[Best_guy].Perf;
New[long_poblacion - 1].n_e = 0;
}
}
/**
* <p>
* Returns the best solution
* </p>
* @return char[] The best solution
*/
public char[] solucion() {
return (New[Best_guy].GeneSel);
}
/**
* <p>
* Returns the fitness of the best solution
* </p>
* @return double The fitness of the best solution
*/
public double solucion_cla() {
return (New[Best_guy].Perf);
}
}