/***********************************************************************
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.io.*;
import org.core.*;
import java.util.*;
import java.lang.Math;
class Mogul {
/**
* <p>
* It learns the initial Rule Base (RB) and Data Base (DB)
* </p>
*/
public int MaxRules;
public int tipo_reglas, compa, repetidas;
public double semilla, epsilon;
public int[] indices_nc;
public int[] Rule_act;
public String fich_datos_chequeo, fich_datos_tst;
public String fichero_conf, fichero_inf, ruta_salida;
public String fichero_datos, fichero_reglas, fich_tra_obli, fich_tst_obli;
public String datos_inter = "";
public String cadenaRules = "";
public Structure Padre, Hijo;
public MyDataset tabla, tabla_tst;
public RuleBase base_reglas;
public DataBase base_datos;
public Adap fun_adap;
public T_FRM FRM;
/**
* <p>
* Constructor
* </p>
* @param f_e String it is the filename of the configuration file.
*/
public Mogul(String f_e) {
fichero_conf = f_e;
}
/**
* <p>
* Removes the blank spaces from a String
* </p>
* @return String The String without blank spaces
*/
private String Remove_spaces(String cadena) {
StringTokenizer sT = new StringTokenizer(cadena, "\t ", false);
return (sT.nextToken());
}
/**
* <p>
* Reads the data of the configuration file
* </p>
*/
public void leer_conf() {
int i, j, n_etiquetas, tipo_fitness;
double omega, K;
String cadenaEntrada, valor;
// we read the file in a String
cadenaEntrada = MyFile.ReadMyFile(fichero_conf);
StringTokenizer sT = new StringTokenizer(cadenaEntrada, "\n\r=", false);
// we read the algorithm's name
sT.nextToken();
sT.nextToken();
// we read the name of the training and test files
sT.nextToken();
valor = sT.nextToken();
StringTokenizer ficheros = new StringTokenizer(valor, "\t ", false);
ficheros.nextToken();
fich_datos_chequeo = ( (ficheros.nextToken()).replace('\"', ' ')).trim();
fich_datos_tst = ( (ficheros.nextToken()).replace('\"', ' ')).trim();
// we read the name of the output files
sT.nextToken();
valor = sT.nextToken();
ficheros = new StringTokenizer(valor, "\t ", false);
fich_tra_obli = ( (ficheros.nextToken()).replace('\"', ' ')).trim();
fich_tst_obli = ( (ficheros.nextToken()).replace('\"', ' ')).trim();
fichero_reglas = ( (ficheros.nextToken()).replace('\"', ' ')).trim(); //Initial RB
fichero_inf = ( (ficheros.nextToken()).replace('\"', ' ')).trim(); //DB
String aux = ( (ficheros.nextToken()).replace('\"', ' ')).trim(); //Simplification output BR
aux = ( (ficheros.nextToken()).replace('\"', ' ')).trim(); //Tuning output RB
ruta_salida = fichero_reglas.substring(0,
fichero_reglas.lastIndexOf('/') + 1);
// we read the seed of the random generator
sT.nextToken();
valor = sT.nextToken();
semilla = Double.parseDouble(valor.trim());
Randomize.setSeed( (long) semilla);
// we read the number of labels
sT.nextToken();
valor = sT.nextToken();
n_etiquetas = Integer.parseInt(valor.trim());
// we read the omega parameter for the maching degree of the positive instances
sT.nextToken();
valor = sT.nextToken();
omega = Double.parseDouble(valor.trim());
// we read the K parameter for the percentage of allowed negative instances
sT.nextToken();
valor = sT.nextToken();
K = Double.parseDouble(valor.trim());
// we read the epsilon parameter for the minimun maching degree required to the KB
sT.nextToken();
valor = sT.nextToken();
epsilon = Double.parseDouble(valor.trim());
// we read if repeated rules are allowed in the population
sT.nextToken();
valor = sT.nextToken();
repetidas = Integer.parseInt(valor.trim());
// we read the type of rule
sT.nextToken();
valor = sT.nextToken();
tipo_reglas = Integer.parseInt(valor.trim());
// we read the type of compability among an example and a antecedent of a rule
sT.nextToken();
valor = sT.nextToken();
compa = Integer.parseInt(valor.trim());
FRM = new T_FRM();
// we read the type of FRM
sT.nextToken();
valor = sT.nextToken();
FRM.fagre = Integer.parseInt(valor.trim());
// we read the param alfa, used in some FRMs
sT.nextToken();
valor = sT.nextToken();
FRM.palfa = Double.parseDouble(valor.trim());
// we read the param p, used in some FRMs
sT.nextToken();
valor = sT.nextToken();
FRM.p = Double.parseDouble(valor.trim());
// we read the param a, used in some FRMs
sT.nextToken();
valor = sT.nextToken();
FRM.a = Double.parseDouble(valor.trim());
// we read the param b, used in some FRMs
sT.nextToken();
valor = sT.nextToken();
FRM.b = Double.parseDouble(valor.trim());
// we read the type of fitness function
// sT.nextToken();
// valor = sT.nextToken();
// tipo_fitness = Integer.parseInt(valor.trim());
tipo_fitness = 1;
// we create all the objects
tabla = new MyDataset(fich_datos_chequeo, true);
base_datos = new DataBase(n_etiquetas, tabla.n_inputs);
// MaxRules = (new Double(Math.pow(n_etiquetas, tabla.n_inputs))).intValue();
MaxRules = tabla.long_tabla;
base_reglas = new RuleBase(MaxRules, base_datos, tabla, tipo_reglas);
fun_adap = new Adap(tabla, base_reglas, FRM, tipo_reglas, compa);
fun_adap.omega = omega;
fun_adap.K = K;
fun_adap.tipo_fitness = tipo_fitness;
indices_nc = new int[tabla.long_tabla];
Rule_act = new int[tabla.n_inputs];
Padre = new Structure(base_reglas.n_genes, tabla.nClasses);
Hijo = new Structure(base_reglas.n_genes, tabla.nClasses);
for (i = 0; i < tabla.n_inputs; i++) {
base_datos.n_etiquetas[i] = n_etiquetas;
base_datos.extremos[i].min = tabla.extremos[i].min;
base_datos.extremos[i].max = tabla.extremos[i].max;
}
}
/**
* <p>
* It launches the algorithm
* </p>
*/
public void run() {
int i, j, pos_individuo, encontrado, contador;
double RCE, min_CR, min_CVR, porcen_tra, porcen_tst, PN, fitness;
/* We read the configutate file and we initialize the structures and variables */
leer_conf();
/* we generate the semantics of the linguistic variables */
base_datos.Semantic();
/* we store the DB in the report file */
String informe = "Initial Data Base: \n\n";
for (i = 0; i < tabla.n_inputs; i++) {
informe += " Variable " + (i + 1) + ":\n";
for (j = 0; j < base_datos.n_etiquetas[i]; j++) {
informe += " Label " + (j + 1) + ": (" +
base_datos.BaseDatos[i][j].x0 + "," + base_datos.BaseDatos[i][j].x1 +
"," + base_datos.BaseDatos[i][j].x3 + ")\n";
}
informe += "\n";
}
informe += "\n";
MyFile.WriteMyFile(fichero_inf, informe);
/* Inicialization of the counters */
tabla.no_cubiertos = tabla.long_tabla;
base_reglas.n_reglas = 0;
/* Iterative Rule Learning */
do {
/* Generation of the better rule */
Generate();
//System.out.println("Number of rules generated: " + (base_reglas.n_reglas + 1));
fun_adap.RulesCriteria(Padre);
fitness = fun_adap.F * fun_adap.G * fun_adap.g;
/* if (fun_adap.tipo_fitness==1) {
PN = fun_adap.LNIR (Padre.Gene);
fitness *= PN;
}
else {
fitness *= fun_adap.PC;
}
*/
encontrado = 0;
if (repetidas == 0) {
/* We look if the rule was previously in the rules structure,
in order to avoid repeated rules in the final RB. */
for (i = 0; i < base_reglas.n_reglas && encontrado == 0; i++) {
contador = 0;
for (j = 0; j < tabla.n_inputs; j++) {
pos_individuo = tabla.n_inputs + 3 * j;
if ( (base_reglas.BaseReglas[i][j].x0 == Padre.Gene[pos_individuo]) &&
(base_reglas.BaseReglas[i][j].x1 ==
Padre.Gene[pos_individuo + 1]) &&
(base_reglas.BaseReglas[i][j].x3 ==
Padre.Gene[pos_individuo + 2])) {
contador++;
}
}
if (contador == tabla.n_inputs) {
encontrado = 1;
}
}
}
if (encontrado == 0) {
/* The rule is stored in the RB */
base_reglas.insert_rule(Padre);
}
else {
System.out.println("Repeated rule");
}
/* we calculate the matching degree of the rule with each example. the covered examples are marked */
for (i = 0; i < tabla.long_tabla; i++) {
RCE = fun_adap.RuleCoversExample(Padre, tabla.datos[i].ejemplo);
tabla.datos[i].nivel_cubrimiento += RCE;
tabla.datos[i].maximo_cubrimiento = Adap.Maximum(tabla.datos[i].
maximo_cubrimiento, RCE);
if ( (tabla.datos[i].nivel_cubrimiento >= epsilon) &&
(tabla.datos[i].cubierto == 0)) {
tabla.datos[i].cubierto = 1;
tabla.no_cubiertos--;
}
}
/* the multimodal GA finish when the condition is true */
}
while (StopCondition() == 0);
System.out.println("Number of rules generated: " + (base_reglas.n_reglas + 1));
/* we calculate the minimum and maximum matching */
min_CR = 1.0;
min_CVR = 10E37;
for (i = 0; i < tabla.long_tabla; i++) {
min_CR = Adap.Minimum(min_CR, tabla.datos[i].maximo_cubrimiento);
min_CVR = Adap.Minimum(min_CVR, tabla.datos[i].nivel_cubrimiento);
}
/* we calcule the clasification percentaje on training */
fun_adap.Clasification_accuracy(true, tabla);
/* we calcule the clasification percentaje on test */
tabla_tst = new MyDataset(fich_datos_tst, false);
fun_adap.Clasification_accuracy(false, tabla_tst);
porcen_tra = fun_adap.ClaTra;
porcen_tst = fun_adap.ClaTst;
/* we write the RB */
cadenaRules = base_reglas.BRtoString();
cadenaRules += "\n%Tra: " + porcen_tra + " %Tst: " + porcen_tst +
"\nMinimun C_R: " + min_CR + " MSE CV_R: " + min_CVR + "\n";
MyFile.WriteMyFile(fichero_reglas, cadenaRules);
/* we write the obligatory output files*/
String salida_tra = tabla.getHeader();
salida_tra += fun_adap.ObligatoryOutputFile(tabla);
MyFile.WriteMyFile(fich_tra_obli, salida_tra);
String salida_tst = tabla_tst.getHeader();
salida_tst += fun_adap.ObligatoryOutputFile(tabla_tst);
MyFile.WriteMyFile(fich_tst_obli, salida_tst);
/* we write the MSEs in specific files */
MyFile.AddtoMyFile(ruta_salida + "MogulFScomunR.txt",
"" + base_reglas.n_reglas + "\n");
MyFile.AddtoMyFile(ruta_salida + "MogulFScomunTRA.txt",
"" + porcen_tra + "\n");
MyFile.AddtoMyFile(ruta_salida + "MogulFScomunTST.txt",
"" + porcen_tst + "\n");
}
/** Returns 1 if the best current rule is in the list "L" yet */
private int Pertenece(int n_generadas) {
int nreg, var, esta;
nreg = 0;
while (nreg < n_generadas) {
esta = 1;
var = 0;
while ( (var < tabla.n_inputs) && (esta == 1)) {
if (Rule_act[var] != base_reglas.Pob_reglas[nreg].Gene[var]) {
esta = 0;
}
else {
var++;
}
}
if (esta == 1) {
return (1);
}
nreg++;
}
return (0);
}
/**
* <p>
* Generates the best rule
* </p>
*/
public void Generate() {
int i, j, k, etiqueta, pos_individuo, n_reg_generadas, indice_mejor, clase;
double grado_pertenencia, max_pert;
/* we obtain the uncovered examples */
i = j = 0;
while ( (i < tabla.no_cubiertos) && (j < tabla.long_tabla)) {
if (tabla.datos[j].cubierto == 0) {
indices_nc[i] = j;
i++;
}
j++;
}
/* we generate the best rule for each example */
n_reg_generadas = 0;
for (i = 0; i < tabla.no_cubiertos; i++) {
/* Determination of the best label for each variable */
for (j = 0; j < tabla.n_inputs; j++) {
max_pert = 0;
etiqueta = 0;
for (k = 0; k < base_datos.n_etiquetas[j]; k++) {
grado_pertenencia = base_reglas.Fuzzification(tabla.datos[indices_nc[i]].
ejemplo[j], base_datos.BaseDatos[j][k]);
if (grado_pertenencia > max_pert) {
max_pert = grado_pertenencia;
etiqueta = k;
}
}
Rule_act[j] = etiqueta;
}
/* if the rule aren't in the set, it's insert */
if (Pertenece(n_reg_generadas) == 0) {
for (j = 0; j < tabla.n_inputs; j++) {
etiqueta = Rule_act[j];
pos_individuo = tabla.n_inputs + 3 * j;
base_reglas.Pob_reglas[n_reg_generadas].Gene[j] = (double) etiqueta;
base_reglas.Pob_reglas[n_reg_generadas].Gene[pos_individuo] =
base_datos.BaseDatos[j][etiqueta].x0;
base_reglas.Pob_reglas[n_reg_generadas].Gene[pos_individuo +
1] = base_datos.BaseDatos[j][etiqueta].x1;
base_reglas.Pob_reglas[n_reg_generadas].Gene[pos_individuo +
2] = base_datos.BaseDatos[j][etiqueta].x3;
}
clase = (int) tabla.datos[indices_nc[i]].ejemplo[tabla.n_inputs];
switch (tipo_reglas) {
case 1:
Consequent_type1(n_reg_generadas, clase);
break;
case 2:
Consequent_type2Mean(n_reg_generadas, clase);
break;
case 3:
Consequent_type3Mean(n_reg_generadas, clase);
}
n_reg_generadas++;
}
}
/* we obtain the best rule */
Padre.Perf = 0;
indice_mejor = 0;
for (i = 0; i < n_reg_generadas; i++) {
base_reglas.Pob_reglas[i].Perf = fun_adap.eval(base_reglas.Pob_reglas[i]);
if (base_reglas.Pob_reglas[i].Perf > Padre.Perf) {
Padre.Perf = base_reglas.Pob_reglas[i].Perf;
indice_mejor = i;
}
}
for (i = 0; i < base_reglas.n_genes; i++) {
Padre.Gene[i] = base_reglas.Pob_reglas[indice_mejor].Gene[i];
}
Padre.Perf = base_reglas.Pob_reglas[indice_mejor].Perf;
switch (tipo_reglas) {
case 1:
case 2:
Padre.Consecuente[0].clase = base_reglas.Pob_reglas[indice_mejor].
Consecuente[0].clase;
Padre.Consecuente[0].gcerteza = base_reglas.Pob_reglas[indice_mejor].
Consecuente[0].gcerteza;
break;
case 3:
for (j = 0; j < tabla.nClasses; j++) {
Padre.Consecuente[j].clase = base_reglas.Pob_reglas[indice_mejor].
Consecuente[j].clase;
Padre.Consecuente[j].gcerteza = base_reglas.Pob_reglas[indice_mejor].
Consecuente[j].gcerteza;
}
}
}
/**
* <p>
* Sets the class of the rule to "clase" and its certainty degree to 1.0
* </p>
* @param regla int The number of rule
* @param clase int The class for the rule "regla"
*/
public void Consequent_type1(int regla, int clase) {
base_reglas.Pob_reglas[regla].Consecuente[0].clase = clase;
base_reglas.Pob_reglas[regla].Consecuente[0].gcerteza = 1.0;
}
/**
* <p>
* Sets the class of the rule to "clase" and calculates its certainty degree
* </p>
* @param regla int The number of rule
* @param clase int The class for the rule "regla"
*/
public void Consequent_type2Mean(int regla, int clase) {
int i, etiqueta, pos_individuo;
double comp, sumaclase, total, cf;
FuzzySet[] D = new FuzzySet[tabla.n_inputs];
/* sumaclases collect the compatibility degree among the antecedent of the
rule and the examples belonging to the class */
sumaclase = 0.0;
total = 0.0;
for (i = 0; i < tabla.n_inputs; i++) {
D[i] = new FuzzySet();
pos_individuo = tabla.n_inputs + 3 * i;
D[i].x0 = base_reglas.Pob_reglas[regla].Gene[pos_individuo];
D[i].x1 = base_reglas.Pob_reglas[regla].Gene[pos_individuo + 1];
D[i].x3 = base_reglas.Pob_reglas[regla].Gene[pos_individuo + 2];
D[i].y = 1;
}
/* We calculate the sum by classes */
for (i = 0; i < tabla.long_tabla; i++) {
comp = fun_adap.MatchingDegree(tabla.datos[i].ejemplo, D);
if (comp > 0.0) {
if ( (int) tabla.datos[i].ejemplo[tabla.n_inputs] == clase) {
sumaclase += comp;
}
total += comp;
}
}
cf = sumaclase / total;
base_reglas.Pob_reglas[regla].Consecuente[0].clase = clase;
base_reglas.Pob_reglas[regla].Consecuente[0].gcerteza = cf;
}
/**
* <p>
* Sets the class of the rule to "clase" and calculates its certainty degree
* </p>
* @param regla int The number of rule
* @param clase int The class for the rule "regla"
*/
public void Consequent_type3Mean(int regla, int clase) {
int i, j, pos, c, pos_individuo;
double comp, total, certeza;
;
int num_clases = tabla.nClasses;
double[] suma_ejemplos = new double[num_clases];
FuzzySet[] D = new FuzzySet[tabla.n_inputs];
/* sumaclases collect the compatibility degree among the antecedent of the
rule and the examples belonging to the class */
for (i = 0; i < num_clases; i++) {
suma_ejemplos[i] = 0.0;
}
total = 0.0;
for (i = 0; i < tabla.n_inputs; i++) {
D[i] = new FuzzySet();
pos_individuo = tabla.n_inputs + 3 * i;
D[i].x0 = base_reglas.Pob_reglas[regla].Gene[pos_individuo];
D[i].x1 = base_reglas.Pob_reglas[regla].Gene[pos_individuo + 1];
D[i].x3 = base_reglas.Pob_reglas[regla].Gene[pos_individuo + 2];
D[i].y = 1;
}
/* We calculate the sum by classes */
for (i = 0; i < tabla.long_tabla; i++) {
comp = fun_adap.MatchingDegree(tabla.datos[i].ejemplo, D);
if (comp > 0.0) {
suma_ejemplos[ (int) tabla.datos[i].ejemplo[tabla.n_inputs]] += comp;
total += comp;
}
}
for (i = 0; i < num_clases; i++) {
base_reglas.Pob_reglas[regla].Consecuente[i].clase = i;
certeza = suma_ejemplos[i] / total;
if (certeza > 0.0) {
base_reglas.Pob_reglas[regla].Consecuente[i].gcerteza = certeza;
}
else {
base_reglas.Pob_reglas[regla].Consecuente[i].gcerteza = 0.0;
}
}
}
/**
* <p>
* Criterion of stop
* </p>
* @return int Returns 1 if it is necessary to stop. 0 otherwise
*/
public int StopCondition() {
if ( (tabla.no_cubiertos == 0) || (base_reglas.n_reglas == MaxRules)) {
return (1);
}
else {
return (0);
}
}
/**
* <p>
* Returns the set of examples
* </p>
* @param train boolean If TRUE returns the training set of examples. If FALSE returns the test training set of examples
* @return MyDatasets The set of examples
*/
public MyDataset getTable(boolean train) {
if (train) {
return tabla;
}
else {
return tabla_tst;
}
}
}