/////////////////////////////////////////////////////////////////////////////////////////////
///Accelerated Particle Swarm Optimization  (by X-S Yang, Cambridge University)
///REFERANCE---> Engineering Optimization : An introduction with Metaheuristic Applications 
/////////////////////////////////////////////////////////////////////////////////////////////
// Chapter 15.3
// Accelerated Particle Swarm Optimization
// Equation 15.6 is used to increase convergence 
/////////////////////////////////////////////////////////////////////////////////////////////

abstract class f_xj
{
abstract double func(double x[]);
}

public class accelerated_particle_swarm_optimization
{
int D;//number of swarm particles in population
int N;//population size
int maxiter;//maximum iteration (generation)
public double xmin[]; // minimum limits of independent variable 
public double xmax[]; //maximum limits of independent variable
double q;
double x[][];// position vector
double fitness[];//fitness value/cost function
double gbest[];
double fgbest;
int igbest;
int iminf;
double minf;
double gamma;// convergence parameter; 0.0<gamma<1.0
double alpha0;// convergence parameter; 0.5<alpha0<1.0
double beta;// convergence parameter; 0.1<beta<0.7
f_xj ff;


     public accelerated_particle_swarm_optimization(f_xj iff,int iN,int imaxiter,double ixmin[],double ixmax[],double ibeta,double ialpha0,double igamma) 
	 {
	 ff=iff;
	 D=ixmin.length;
	 N=iN;	 
	 maxiter=imaxiter;
	 alpha0=ialpha0;
	 beta=ibeta;
	 gamma=igamma;
	 xmin=new double[D];	 
	 xmax=new double[D];
	 x=new double[N][D];	 
	 fitness=new double[N];
	 gbest=new double[D];
	 for(int i=0;i<D;i++)
	 {xmin[i]=ixmin[i];xmax[i]=ixmax[i];}
	}
	 
	 void initialize()
	 {
	  for(int i=0;i<N;i++)
	  {for(int j=0;j<D;j++)
	   {x[i][j]=xmin[j]+((xmax[j]-xmin[j])*Math.random());}	  
	   fitness[i]=ff.func(x[i]);}
	   double[] dep=getminval_index(fitness);
	   fgbest=dep[0];
	   igbest=(int)dep[1];
	   gbest=x[igbest];	 
	  
	   
	 }
	
	 double[] getminval_index(double[] a)
	 {
	 double m=0.0;	 
	 double b[]=new double[a.length];
	 for(int i=0;i<a.length;i++)
	 {b[i]=a[i];}  
	 double minval=a[0];
	 for(int i=0;i<a.length;i++)
	 {if(a[i]<minval){minval=a[i];}}
	 for(int i=0;i<a.length;i++)
	 {if(b[i]==minval){m=i;break;}};
	 double[] dep=new double[2];
	 dep[0]=minval;
	 dep[1]=m;
	 return dep;	 
	 } 
	 
	 double newalpha(double tt) // improves algorithm by reducing randomness
	 {return alpha0*Math.exp(-gamma*tt);}
	 
	 double[] simplebounds(double s[])
	 {
	   for(int i=0;i<D;i++)
	   {if(s[i]<xmin[i])
	    {s[i]=xmin[i];}
	    if(s[i]>xmax[i])
	    {s[i]=xmax[i];}
	   }	 
	   return s;	 
	 }
	 
	 void solution()
	 {
	  initialize();
	  int iter=0; 
	  double tt=0.0;
	  	while(iter<maxiter)
	  	{
		 for(int i=0;i<N;i++)
		 {for(int j=0;j<D;j++)
		  {x[i][j]=(x[i][j]*(1.0-beta))+(beta*gbest[j])+(newalpha(tt)*(Math.random()-0.5));} 
		  x[i]=simplebounds(x[i]);// Apply upper and lower bound
		  fitness[i]=ff.func(x[i]);}
		  double[] dep=getminval_index(fitness);// finds minimum value of a vector and its index
		  minf=dep[0];
		  iminf=(int)dep[1];
		  if(minf<fgbest)
		  {fgbest=minf;
		  for(int ii=0;ii<D;ii++)
		  {gbest[ii]=x[iminf][ii];}
		  }
		  tt++; 	
		 iter++; 	
		} 
		System.out.println("Optimum value = "+fgbest);
		for(int i=0;i<D;i++)
		{System.out.println("x["+i+"] = "+gbest[i]);}
		
	}
	 
	 
	
	
	
}