/***********************************************************************
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/
**********************************************************************/
/*
PSO.java
Isaac Triguero Velazquez.
Created by Isaac Triguero Velazquez 11-8-2008
Copyright (c) 2008 __MyCompanyName__. All rights reserved.
*/
package keel.Algorithms.Instance_Generation.PSO;
import keel.Algorithms.Instance_Generation.Basic.PrototypeSet;
import keel.Algorithms.Instance_Generation.Basic.PrototypeGenerator;
import keel.Algorithms.Instance_Generation.Basic.Prototype;
import keel.Algorithms.Instance_Generation.Basic.PrototypeGenerationAlgorithm;
import keel.Algorithms.Instance_Generation.Chen.ChenGenerator;
import keel.Algorithms.Instance_Generation.HYB.HYBGenerator;
import keel.Algorithms.Instance_Generation.*;
import java.util.*;
import keel.Algorithms.Instance_Generation.utilities.*;
import keel.Algorithms.Instance_Generation.utilities.KNN.*;
import keel.Dataset.Attributes;
import org.core.*;
import org.core.*;
import java.util.StringTokenizer;
/**
*
* @param k
* @param SwarmSize
* @param Particle Size
* @param MaxIter
* @param C1
* @param C2
* @param VMax
* @param Wstart
* @param Wend
* @author Isaac Triguero
* @version 1.0
*/
public class PSOGenerator extends PrototypeGenerator {
/*Own parameters of the algorithm*/
// We need the variable K to use with k-NN rule
private int k;
private int SwarmSize; // SwarmSize == P
private int ParticleSize; // ParticleSize == K (in the article)
private int MaxIter;
private double C1;
private double C2;
private double VMax;
private double Wstart;
private double Wend;
protected int numberOfPrototypes; // Particle size is the percentage
protected int numberOfClass;
/** Parameters of the initial reduction process. */
private String[] paramsOfInitialReducction = null;
/**
* Build a new PSOGenerator Algorithm
*/
public PSOGenerator(PrototypeSet _trainingDataSet, int neigbors,int poblacion, int perc, int iteraciones, double c1, double c2, double vmax, double wstart, double wend)
{
super(_trainingDataSet);
algorithmName="PSO";
this.k = neigbors;
this.SwarmSize = poblacion;
this.ParticleSize = perc;
this.MaxIter = iteraciones;
this.numberOfPrototypes = getSetSizeFromPercentage(perc);
this.C1 = c1;
this.C2 = c2;
this.VMax = vmax;
this.Wend = wend;
this.Wstart = wstart;
}
/**
* Build a new PSOGenerator Algorithm
* @param t Original prototype set to be reduced.
* @param parameters Parameters of the algorithm (only % of reduced set).
*/
public PSOGenerator(PrototypeSet t, Parameters parameters)
{
super(t, parameters);
algorithmName="PSO";
this.k = parameters.getNextAsInt();
this.SwarmSize = parameters.getNextAsInt();
this.ParticleSize = parameters.getNextAsInt();
this.MaxIter = parameters.getNextAsInt();
this.C1 = parameters.getNextAsDouble();
this.C2 = parameters.getNextAsDouble();
this.VMax = parameters.getNextAsDouble();
this.Wstart = parameters.getNextAsDouble();
this.Wend = parameters.getNextAsDouble();
this.numberOfClass = trainingDataSet.getPosibleValuesOfOutput().size();
this.numberOfPrototypes = getSetSizeFromPercentage(ParticleSize);
System.out.print("\nIsaac dice: " + k + " Swar= "+SwarmSize+ " Particle= "+ ParticleSize + " Maxiter= "+ MaxIter+" Wend= "+Wend+ "\n");
//numberOfPrototypes = getSetSizeFromPercentage(parameters.getNextAsDouble());
}
/**
* Generate a reduced prototype set by the PSOGenerator method.
* @return Reduced set by PSOGenerator's method.
*/
public PrototypeSet reduceSet()
{
System.out.print("\nThe algorithm is starting...\n Computing...\n");
System.out.println("Number of prototypes, result set = "+numberOfPrototypes+ "\n");
System.out.println("Reduction %, result set = "+((trainingDataSet.size()-numberOfPrototypes)*100)/trainingDataSet.size()+ "\n");
//trainingDataSet.getFromClass(0).print();
//Algorithm
// First, we create the population, with SwarmSize.
// like a prototypeSet's vector.
PrototypeSet population [] = new PrototypeSet [SwarmSize];
PrototypeSet mejorPosicion [] = new PrototypeSet [SwarmSize];
PrototypeSet nominalPopulation = new PrototypeSet();
double fitness[] = new double[SwarmSize];
double fitness_bestPopulation[] = new double[SwarmSize];
PrototypeSet bestParticle = new PrototypeSet();
double inertia = ((Wstart-Wend)*(MaxIter))/ (MaxIter + Wend);
int mejorParticula =0; // The best particle in the population
double aleatorio;
//Each particle must have Particle Size %
// trainingDataSet.print();
population[0]= new PrototypeSet(selecRandomSet(numberOfPrototypes,true).clone()) ;
fitness[0] = accuracy(population[0],trainingDataSet);
// Aseguro que al menos hay un representante de cada clase.
PrototypeSet clases[] = new PrototypeSet [this.numberOfClass];
for(int i=0; i< this.numberOfClass; i++){
clases[i] = new PrototypeSet(trainingDataSet.getFromClass(i));
System.out.println("Clase"+i +" : "+clases[i].size());
}
for(int i=0; i< population[0].size(); i++){
for(int j=0; j< this.numberOfClass; j++){
if(population[0].getFromClass(j).size() ==0 && clases[j].size()!=0){
Prototype aux = new Prototype(clases[j].getRandom());
population[0].add(aux);
}
}
}
population[0].print();
for(int i=1; i< SwarmSize; i++){
population[i] = new PrototypeSet();
for(int j=0; j< population[0].size(); j++){
Prototype aux = new Prototype(trainingDataSet.getFromClass(population[0].get(j).getOutput(0)).getRandom());
population[i].add(aux);
}
fitness[i] = accuracy(population[i],trainingDataSet); // PSOfitness
fitness_bestPopulation[i] = fitness[i]; // Initially the same fitness.
}
// population[0].print();
/*
for(int i=0; i< SwarmSize; i++){
population[i]=selecRandomSet(numberOfPrototypes,true).clone() ;
fitness[i] = absoluteAccuracyKNN(population[i], trainingDataSet,k); // PSO fitness
fitness_bestPopulation[i] = fitness[i]; // Initially the same fitness.
// System.out.print("Fitness " + i + " = "+ fitness[i] + "\n");
//System.out.print("\nPoblaci�n " + i + "\n");
//population[i].print();
}*/
//We select the best initial particle
double bestFitness=fitness[0];
int bestFitnessIndex=0;
for(int i=1; i< SwarmSize;i++){
if(fitness[i]>bestFitness){
bestFitness = fitness[i];
bestFitnessIndex=i;
}
}
for(int j=0;j<SwarmSize;j++){
mejorPosicion[j] = population[j].clone(); // hard-copy.Save the best position of the particle.
//Initial mejorPosicion = initial population.
//Now, I establish the index of each prototype.
for(int i=0; i<population[j].size(); ++i)
population[j].get(i).setIndex(i);
}
double velocidad[][][] = new double[SwarmSize][][]; // tri-dimensional vector
int num_atribs = population[0].get(0).numberOfInputs();
for(int i=0; i<SwarmSize;i++){
velocidad[i]= new double[population[0].size()][]; // velocity matrix.
// Initially there is no velocity, no memory..
for(int j=0; j<population[0].size();j++){
velocidad[i][j] = new double[num_atribs];
for(k=0; k<num_atribs;k++){
velocidad[i][j][k] = RandomGenerator.Randdouble(-VMax, VMax)*1. ; // the initial velocity, a random number between -Vmax , Vmax
// System.out.println(velocidad[i][j][k]);
}
}
}
for(int iter=0; iter< MaxIter; iter++){ // Main loop
for(int i=0; i< SwarmSize; i++){
for(int k = 0; k< population[i].size();k++){
Prototype resta = mejorPosicion[i].get(k).sub(population[i].get(k));
Prototype restaBestParticle = mejorPosicion[bestFitnessIndex].get(k).sub(population[i].get(k));
for(int j=0; j< num_atribs ; j++){
velocidad[i][k][j]= inertia * velocidad[i][k][j] ; // Memory velocity.
aleatorio =RandomGenerator.Randdouble(0, 1) ;
velocidad[i][k][j]+= C1*aleatorio* resta.getInput(j) ; // Cognition part.
aleatorio =RandomGenerator.Randdouble(0, 1) ;
velocidad[i][k][j]+= C2*aleatorio * restaBestParticle.getInput(j) ; // Social part.
//System.out.print(aleatorio + "\t");
// Then we do xi = xi + vi.
if(velocidad[i][k][j]>VMax){
velocidad[i][k][j] = VMax; // The particles's velocities has a maximum velocity.
}else if(velocidad[i][k][j]< -VMax){
velocidad[i][k][j]=-VMax; // absolute value. �? or -VMax , Vmax. ?
}
//System.out.print("\nVelocidad ="+ velocidad[i][k][j] + "\n");
// System.out.print("\nvalor= "+ population[i].get(k).getInput(j)+ "\n");
double suma = population[i].get(k).getInput(j) + velocidad[i][k][j]*1.;
//if(suma>1) suma = 1;
//else if( suma<0) suma = 0; // Establish the normalize limits [0,1]
//System.out.print("\nSuma= "+ suma+ "\n");
population[i].get(k).setInput(j,suma); // We add the velocity to the attribute
population[i].get(k).applyThresholds();
}
}
}
//Now we have xi = xi + vi.for all particles.
// Particles has changed, We must calculate fitness and compare all.
for(int i=0; i< SwarmSize; i++){
/*
if(k<=population[i].size())
fitness[i] = absoluteAccuracyKNN(population[i], trainingDataSet,k); // PSO fitness
else
fitness[i] = absoluteAccuracyKNN(population[i],trainingDataSet,population[i].size());
*/
// Antes de calcular el fitness, tengo que "transformar los datos nominales.."
nominalPopulation = new PrototypeSet();
nominalPopulation.formatear(population[i]);
fitness[i] = accuracy(nominalPopulation,trainingDataSet);
//fitness[i] = accuracy(population[i],trainingDataSet);
}
for(int i=0; i< SwarmSize;i++){
// Where is the best?
if(fitness[i]>bestFitness){
bestFitness = fitness[i];
bestFitnessIndex=i;
}
//Save the best particles!
if(fitness[i]>fitness_bestPopulation[i]){
fitness_bestPopulation[i] = fitness[i];
mejorPosicion[i] = population[i].clone(); // Hard Copy.
}
}
//Calculate the new inertia.
inertia = ((Wstart-Wend)*(MaxIter-iter))/ (MaxIter + Wend);
}
// PrototypeSet result = new PrototypeSet(SwarmSize);
/*for(int i=0; i<SwarmSize; ++i)
{
// Prototype averaged = C.get(i).avg();
// double averagedClass = C.get(i).mostFrequentClass();
// averaged.setLabel(averagedClass);
//result.add(averaged);
//System.out.println("Prototipo " + i + " tiene clase " + averagedClass);
}*/
// System.out.println("Best fitness= "+bestFitness);
//System.out.println("Generated set \n");
//mejorPosicion[bestFitnessIndex].print();
nominalPopulation = new PrototypeSet();
nominalPopulation.formatear(mejorPosicion[bestFitnessIndex]);
// System.err.println("\n% de acierto en training Nominal " + PSOGenerator.accuracy(nominalPopulation, trainingDataSet) );
// trainingDataSet.getFromClass(0).print();
// System.err.println("\n% de acierto en training " + PSOGenerator.accuracy(mejorPosicion[bestFitnessIndex], trainingDataSet) );
//return mejorPosicion[bestFitnessIndex];
return nominalPopulation;
}
/**
* General main for all the prototoype generators
* Arguments:
* 0: Filename with the training data set to be condensed.
* 1: Filename which contains the test data set.
* 3: Seed of the random number generator. Always.
* **************************
* 4: .Number of neighbors
* 5: Swarm Size
* 6: Particle Size
* 7: Max Iter
* 8: C1
* 9: c2
* 10: vmax
* 11: wstart
* 12: wend
* @param args Arguments of the main function.
*/
public static void main(String[] args)
{
Parameters.setUse("PSO", "<seed> <Number of neighbors>\n<Swarm size>\n<Particle Size>\n<MaxIter>\n<DistanceFunction>");
Parameters.assertBasicArgs(args);
PrototypeSet training = PrototypeGenerationAlgorithm.readPrototypeSet(args[0]);
PrototypeSet test = PrototypeGenerationAlgorithm.readPrototypeSet(args[1]);
long seed = Parameters.assertExtendedArgAsInt(args,2,"seed",0,Long.MAX_VALUE);
PSOGenerator.setSeed(seed);
int k = Parameters.assertExtendedArgAsInt(args,3,"number of neighbors", 1, Integer.MAX_VALUE);
int swarm = Parameters.assertExtendedArgAsInt(args,4,"swarm size", 1, Integer.MAX_VALUE);
int particle = Parameters.assertExtendedArgAsInt(args,5,"particle size", 1, Integer.MAX_VALUE);
int iter = Parameters.assertExtendedArgAsInt(args,6,"max iter", 1, Integer.MAX_VALUE);
double c1 = Parameters.assertExtendedArgAsInt(args,7,"c1", 1, Double.MAX_VALUE);
double c2 =Parameters.assertExtendedArgAsInt(args,8,"c2", 1, Double.MAX_VALUE);
double vmax =Parameters.assertExtendedArgAsInt(args,9,"vmax", 1, Double.MAX_VALUE);
double wstart = Parameters.assertExtendedArgAsInt(args,10,"wstart", 1, Double.MAX_VALUE);
double wend =Parameters.assertExtendedArgAsInt(args,11,"wend", 1, Double.MAX_VALUE);
//String[] parametersOfInitialReduction = Arrays.copyOfRange(args, 4, args.length);
//System.out.print(" swarm ="+swarm+"\n");
PSOGenerator generator = new PSOGenerator(training, k,swarm,particle,iter, c1,c2,vmax,wstart,wend );
PrototypeSet resultingSet = generator.execute();
//resultingSet.save(args[1]);
//int accuracyKNN = KNN.classficationAccuracy(resultingSet, test, k);
int accuracy1NN = KNN.classficationAccuracy(resultingSet, test);
generator.showResultsOfAccuracy(Parameters.getFileName(), accuracy1NN, test);
}
}