/***********************************************************************
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/
**********************************************************************/
/**
* <p>
* @file RbfnPopulation.java
* @author Written by Victor Manuel Rivas Santos (University of Jaen) 15/08/2007
* @version 0.1
* @since JDK1.5
*</p>
**/
package keel.Algorithms.Neural_Networks.EvRBF_CL;
import org.core.*;
import java.util.*;
import java.io.*;
public class RbfnPopulation {
/**
* <p>
* Implements a population of Radial basis Function Neural Networks to be evolved with EvRBFN_CL
* </p>
*/
/** Number of individuals thet population contains. */
int popSize;
/** The individuals **/
Rbfn [] population;
/** The individuals to who operators will be applied**/
Rbfn [] subPopulation;
/** Min and Max values for data (needed for operators) */
double [] minValues,maxValues;
double MUTATORS_INTERNAL_PROB=0.5;
/**
* <p>
* Creates a new instance of RbfnPopulation
* </p>
* @param _size Size of population
*/
public RbfnPopulation(int _size ) {
try {
population=new Rbfn[_size];
popSize=population.length;
}
catch (Exception e) {
throw new InternalError(e.toString());
}
}
/**
* <p>
* Creates and initializes a population using a set of data.
* </p>
* @param _size Number of nets in the population
* @param _X Set of input patterns
* @param _ndatos Number of input patterns
* @param _nEnt Dimension of input space
* @param _nSal Dimension of output space
* @param _neuronsPercentage Percentage of _ndatos used as upper boundary for the number of neurons
*/
public RbfnPopulation(int _size, double [][] _X,
int _ndatos,int _nEnt,int _nSal,
double _neuronsPercentage ) {
try {
RBFUtils.verboseln( "Initializing population of RBFNs with "+_size+" individuals ");
population=new Rbfn[_size];
popSize=population.length;
int maxNeurons=(int)( _X.length*_neuronsPercentage);
maxNeurons=(maxNeurons<2)?2:maxNeurons;
for( int i=0; i< popSize; ++i ) {
int nNeurons=(int)Randomize.Randint( 2, maxNeurons );
population[i]=new Rbfn( _X , _ndatos , _nEnt, _nSal,nNeurons);
}
set_min_max_values( _X, _ndatos, _nEnt );
} catch (Exception e) {
throw new InternalError(e.toString());
}
}
/**
* <p>
* Setting the mix and max values for data (needed for operators)
* </p>
* @param _X Data
* @param _ndatos Number of data (could differ from _X.length)
* @param _nEnt Input dimension
*/
public void set_min_max_values(double [][] _X, int _ndatos, int _nEnt) {
minValues=new double[_nEnt];
maxValues=new double[_nEnt];
for (int i = 0; i < _nEnt; ++i) {
maxValues[i]=minValues[i]=_X[0][i];
}
for (int j = 1; j < _ndatos; ++j) {
for (int i = 0; i <_nEnt ; ++i) {
minValues[i]=(minValues[i]>_X[j][i])?_X[j][i]:minValues[i];
maxValues[i]=(maxValues[i]<_X[j][i])?_X[j][i]:maxValues[i];
}
}
}
/**
* <p>
* Trains a Population of RBFNs
* </p>
* @param _X Set ot input patterns
* @param _Y Set of output values
* @param _nDatos Number of patterns in _X
* @param _LMSLoops NUmber of iterations for LMS
* @param _delta Delta parameter for LMS
*/
public void trainLMS(double [][] _X, double [][] _Y,
int _nDatos, int _LMSLoops, double _delta ) {
try {
RBFUtils.verboseln( "Training population of RBFNs with "+popSize+" individuals ");
for( int i=0; i< popSize; ++i ) {
population[i].LMSTrain(_X, _Y, _nDatos, _LMSLoops, _delta );
}
} catch (Exception e) {
throw new InternalError(e.toString());
}
}
/**
* <p>
* Sets the fitness of a Population of RBFNs for classification problems
* </p>
* @param _X array containing the input patterns
* @param _Y array containing the desired output (although only first column is used)
* @param _nDatos Number of patterns
* @param _nClases Number of diferent classes
*/
public void setFitness_Cl(double [][] _X, double [][] _Y, int _nDatos, int _nClases ) {
try {
int [] yielded=new int[_nDatos];
int [] auxY=new int[_nDatos];
for( int i=0; i<_nDatos; ++i) {
auxY[i]=(int) _Y[i][0];
}
RBFUtils.verboseln( "Setting the fitness of "+popSize+" individuals ");
for( int i=0; i< popSize; ++i ) {
population[i].classificationTest( _X, _nDatos, yielded, _nClases, 0);
double tmpDoub=(double) RBFUtils.computeMatches( auxY, yielded, _nDatos )/_nDatos;
population[i].setFitness( tmpDoub );
}
} catch (Exception e) {
throw new InternalError(e.toString());
}
}
/**
* <p>
* Trains a Population of RBFNs
* </p>
* @param _X Set ot input patterns
* @param _Y Set of output values
* @param _nDatos Number of patterns in _X
* @param _LMSLoops NUmber of iterations for LMS
* @param _delta Delta parameter for LMS
*/
public void trainLMS_subPop(double [][] _X, double [][] _Y,
int _nDatos, int _LMSLoops, double _delta ) {
try {
RBFUtils.verboseln( "Training supPopulation of RBFNs with "+subPopulation.length+" individuals ");
for( int i=0; i< subPopulation.length; ++i ) {
subPopulation[i].LMSTrain(_X, _Y, _nDatos, _LMSLoops, _delta );
}
} catch (Exception e) {
throw new InternalError(e.toString());
}
}
/**
* <p>
* Sets the fitness of a Sub-Population of RBFNs for classification problems
* </p>
* @param _X array containing the input patterns
* @param _Y array containing the desired output (although only first column is used)
* @param _nDatos Number of patterns
* @param _nClases Number of diferent classes
*/
public void setFitness_Cl_subPop(double [][] _X, double [][] _Y, int _nDatos, int _nClases ) {
try {
int [] yielded=new int[_nDatos];
int [] auxY=new int[_nDatos];
for( int i=0; i<_nDatos; ++i) {
auxY[i]=(int) _Y[i][0];
}
RBFUtils.verboseln( "Setting the fitness of "+subPopulation.length+" individuals ");
for( int i=0; i< subPopulation.length; ++i ) {
subPopulation[i].classificationTest( _X, _nDatos, yielded, _nClases, 0);
subPopulation[i].setFitness( (double) RBFUtils.computeMatches( auxY, yielded, _nDatos )/_nDatos );
}
} catch (Exception e) {
throw new InternalError(e.toString());
}
}
/**
* <p>
* Creates a subPopulation of individuals using the tournament method.
* </p>
* @param _subPopSize Number of individuals to select
* @param _tournamentSize Number of individuals to perform the tournament
*/
public void selectIndividuals( int _subPopSize, int _tournamentSize ) {
// Setting the parameters to correct numbers
_subPopSize=(_subPopSize<1)?1:_subPopSize;
_subPopSize=(_subPopSize>popSize)?popSize:_subPopSize;
_tournamentSize=(_tournamentSize<2)?2:_tournamentSize;
_tournamentSize=(_tournamentSize>popSize)?popSize:_tournamentSize;
// Initializing subPopulation
subPopulation=new Rbfn[_subPopSize];
// Selecting the individuals
for (int i=0; i<_subPopSize; ++i ) {
// select _tournamentSize individuals
int selected=(int)Randomize.Randint( 0,popSize-1);
for( int j=1; j<_tournamentSize; ++j ){
int ran=(int)Randomize.Randint( 0,popSize-1);
selected=(population[selected].getFitness()>population[ran].getFitness())?selected:ran;
}
//System.out.println( "Seleccionado por torneo "+selected );
subPopulation[i]=(Rbfn) population[selected].clone();
}
}
/**
* <p>
* Applies operator according to their probabilities
* </p>
* @param _xOverRate Probability for XOver operators
* @param _mutatorRate Probability for Mutation operators
*/
public void applyOperators( double _xOverRate, double _mutatorRate ) {
for (int i = 0; i < subPopulation.length; ++i) {
double ran=(double) Randomize.Randdouble( 0, _xOverRate+_mutatorRate );
if ( ran<=_xOverRate ) {
// XOver operators
//x_fix( subPopulation[i] );
} else {
// Mutation operators
switch( (int) Randomize.Randint( 0,4 ) ) {
case 0: c_random( subPopulation[i] ); break;
case 1: r_random( subPopulation[i] ); break;
case 2: deleter( subPopulation[i] ); break;
case 3: adder( subPopulation[i] ); break;
}
}
}
}
/**
* <p>
* Removes worse _numIndividuals nets from Population and includes individuals from subpopulation
* </p>
* @param _numIndividuals Number of indivuals to replace
*/
public void replaceIndividuals( int _numIndividuals ){
_numIndividuals=(_numIndividuals>subPopulation.length)?subPopulation.length:_numIndividuals;
sort_population();
for (int i = 0; i < _numIndividuals; ++i) {
population[popSize-i-1]=(Rbfn) subPopulation[i].clone();
}
sort_population();
//System.out.println( " - Best fitness: " +population[0].getFitness() );
}
/**
* <p>
* Shows the _size first individuals (sorted by fitness)
* </p>
* @param _size Number of individuals to show
*/
public void paint_sort(int _size ) {
System.out.println( "Sorted population" );
for( int i=0; i<((popSize>_size)?_size:popSize); ++i ){
System.out.println( " Indiv. "+i+":\t"+
population[i].getFitness()+"\t-\t"+population[i].rbfSize()+"" );
}
}
/**
* <p>
* Sorts population
* </p>
*/
public void sort_population() {
Rbfn tmpNet;
for( int i=0; i<popSize; ++i ){
for (int j = i+1; j <popSize ; ++j) {
if( population[i].getFitness()<population[j].getFitness() ||
(population[i].getFitness()==population[j].getFitness() &&
population[i].rbfSize()>population[j].rbfSize()) ) {
tmpNet=population[i];
population[i]=population[j];
population[j]=tmpNet;
}
}
}
}
/**
* <p>
* Performs the X_FIX crossover operator: replaces numNeurons neurons from
* _net, taking numNeurons from a randomly chosen net.
* </p>
* @param _net The net to be modified
*/
public void x_fix( Rbfn _net ) {
try {
// Select an individual to XOver
Rbfn tmpNet=population[(int) Randomize.Randint( 0, population.length )];
if (_net.rbfSize()<1 || tmpNet.rbfSize()<1 ) {
throw new InternalError("Trying to apply x_fix operator to a net with less than 1 neuron!\n");
}
// Select the number of neurons to interchange; Range: [1,MinNumber of neurons]
int numNeurons=(int) Randomize.Randint( 0, ((_net.rbfSize()<tmpNet.rbfSize() )?_net.rbfSize():tmpNet.rbfSize()) )+1;
// sp stands for starting-point
int sp1=(int) Randomize.Randint( 0, _net.rbfSize()-numNeurons );
int sp2=(int) Randomize.Randint( 0, tmpNet.rbfSize()-numNeurons );
// Remove neurons from _net
String [] indexes=_net.getIndexes();
for( int i=sp1; i<sp1+numNeurons; ++i ) {
_net.removeRbf( indexes[i] );
}
// Add neurons from tmpNet
indexes=tmpNet.getIndexes();
for( int i=sp2; i<sp2+numNeurons; ++i ) {
// Victor Rivas: 21-Aug-2007 (my mark: ????)
// For simplicity (and lack of time) reasons, I give a new id to the neuron
// since I am getting null neurons when inserting RBF with its id existing in the net
// This could (should) be reviewed.
_net.insertRbf( (Rbf) tmpNet.getRbf( indexes[i] ).clone(), RBFUtils.createIdRbf() );
}
} catch (Exception e){
throw new InternalError(e.toString());
}
} // X_FIX
/**
* <p>
* Performs the C_RANDOM mutator operator: modifies MUTATORS_INTERNAL_PROB % of the centers of the net
* </p>
* @param _net The net to be modified
*/
public void c_random( Rbfn _net ) {
try {
// Victor Rivas: 21-Aug-2007 (my mark: ????)
// If X_FIX is changed, then review this method so that the RBF
// (once modified) have a new id
String [] indexes=_net.getIndexes();
for( int i=0; i<indexes.length; ++i ) {
if( Randomize.Randdouble(0,1)<MUTATORS_INTERNAL_PROB ) { // Apply operator
Rbf tmpNeuron=_net.getRbf(indexes[i]);
double [] centers=tmpNeuron.getCenter();
for (int j = 0; j <centers.length ; ++j) {
centers[j]=(double)Randomize.Randdouble(minValues[j],maxValues[j]);
}
tmpNeuron.setCenter( centers );
}
}
} catch (Exception e){
throw new InternalError(e.toString());
}
} // C_RANDOM
/**
* <p>Performs the R_RANDOM mutator operator: modifies 50% of the Radius of the net</p>
* @param _net The net to be modified
*/
public void r_random( Rbfn _net ) {
try {
// Victor Rivas: 21-Aug-2007 (my mark: ????)
// If X_FIX is changed, then review this method so that the RBF
// (once modified) have a new id
String [] indexes=_net.getIndexes();
for( int i=0; i<indexes.length; ++i ) {
if( Randomize.Randdouble(0,1)<MUTATORS_INTERNAL_PROB ) { // Apply operator
Rbf tmpNeuron=_net.getRbf(indexes[i]);
double radius=(double)Randomize.Randdouble(0.5,10); // ???? porqué 0.5 y 10??
tmpNeuron.setRadius( radius );
}
}
} catch (Exception e){
throw new InternalError(e.toString());
}
} // R_RANDOM
/**
* <p>
* Performs the DELETER mutator operator: modifies C_DELETER% of the Radius of the net
* </p>
* @param _net The net to be modified
*/
public void deleter( Rbfn _net ) {
try {
String [] indexes=_net.getIndexes();
for( int i=0; i<indexes.length; ++i ) {
if( Randomize.Randdouble(0,1)<MUTATORS_INTERNAL_PROB ) { // Apply operator
if ( _net.rbfSize()>1 ) {_net.removeRbf(indexes[i]);};
}
}
} catch (Exception e){
throw new InternalError(e.toString());
}
} // DELETER
/**
* <p>
* Performs the DELETER mutator operator: modifies C_DELETER% of the Radius of the net
* </p>
* @param _net The net to be modified
*/
public void adder( Rbfn _net ) {
try {
String [] indexes=_net.getIndexes();
int nEnt=_net.numInputs();
int nSal=_net.numOutputs();
for( int i=0; i<indexes.length; ++i ) {
if( Randomize.Randdouble(0,1)<MUTATORS_INTERNAL_PROB ) { // Apply operator
Rbf newNeuron=new Rbf( nEnt, nSal );
double [] aCenter=new double[nEnt];
for ( int j=0; j<nEnt; ++j ) {
aCenter[j]=Randomize.Randdouble( minValues[j], maxValues[j] );
}
newNeuron.setCenter( aCenter );
//radius is 1/2 the eucidean distance to the neuron
newNeuron.setRadius( RBFUtils.euclidean( newNeuron.getCenter(), _net.getRbf( indexes[i] ).getCenter() )/2 );
_net.insertRbf( newNeuron );
}
}
} catch (Exception e){
throw new InternalError(e.toString());
}
} // ADDER
/**
* <p>
* Prints the ppulation on a stdout
* </p>
*/
public void paint( ) {
this.paint( "" );
}
/**
* <p>
* Prints the pipulation on a file.
* </p>
* @param _fileName Name of the file.
*/
public void paint( String _fileName ) {
if ( _fileName!="" ) {
Files.addToFile( _fileName,"Printing population of RRBFNs\n" );
}
else {
System.out.println("Printing population of RRBFNs\n");
}
for (int i = 0; i < popSize; ++i) {
population[i].paint( _fileName );
}
}
/**
* <p>
* Returns the _num-th individuals
* </p>
* @param _num Position of the individual to return
* @return The _num-th individual of the population
*/
public Rbfn individual( int _num ) {
try {
return population[_num];
}
catch (Exception e) {
throw new InternalError(e.toString());
}
}
} /*end of the class*/