import java.util.Random;
////////////////////////////////////////////////////
// Bat inspired algorithm for continous optimisation
// Xin-She Yang ////////////////////////////////////
////////////////////////////////////////////////////
//REFERANCE
//1) Yang X.-S., A new metaheuristic bat-inspired algorithm,        
//    in: Nature Inspired Cooperative Strategies for Optimization    
//   (NISCO 2010) (Eds. J. R. Gonzalez et al.), Studies in          
//   Computational Intelligence, Springer, vol. 284, 65-74 (2010).  
// 2) Yang X.-S., Nature-Inspired Metaheuristic Algorithms,          
//    Second Edition, Luniver Presss, Frome, UK. (2010).             
// 3) Yang X.-S. and Gandomi A. H., Bat algorithm: A novel           
//   approach for global engineering optimization,                  
//   Engineering Computations, Vol. 29, No. 5, pp. 464-483 (2012). 
//   Programmer : Ošuz Emrah Turgut 
/////////////////////////////////////////////////////////////////////

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

public class bat_inspired_algorithm
{
int n;
int Ngen;
double A;
double r;
double Qmin;
double Qmax;
int Niter;
int d;
double xmin[];
double xmax[];
double Q[];
double v[][];
double[][] Sol;
double[][] S;
double[] fitness;
double[] best;
double fmin;
f_xj ff;

     public bat_inspired_algorithm(f_xj iff,int in,int iNgen,double iA,double ir,double iQmin,double iQmax,double ixmin[],double ixmax[])
     {
	 n=in;
	 Ngen=iNgen;
	 A=iA;
	 r=ir;
	 Qmin=iQmin;
	 Qmax=iQmax;
	 d=ixmin.length;
	 ff=iff;
	 xmin=new double[d];
	 xmax=new double[d];
	 Sol=new double[n][d];
	 S=new double[n][d];
	 fitness=new double[n];
	 best=new double[d];
	 for(int i=0;i<d;i++)
	 {xmin[i]=ixmin[i];xmax[i]=ixmax[i];}
	 Q=new double[n];
	 v=new double[n][d];
	 }
	 
	 void initialize()
	 {
	  
	 for(int i=0;i<n;i++)
	 {for(int j=0;j<d;j++)
	  {Sol[i][j]=xmin[j]+(xmax[j]-xmin[j])*Math.random();}
	  	fitness[i]=ff.func(Sol[i]);}
	  	double d1[]=getminval_index(fitness);
	  	fmin=d1[0];
	  	int index=(int)d1[1];
	  	best=Sol[index];
	 }
	 
	 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[] 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()
	 {
	  int t=1;
	  initialize();
	  Random rndm=new Random();
	  double fnew=0.0;	 
	  while(t<Ngen)
	  {
		for(int i=0;i<n;i++)
		{
		  Q[i]=Qmin+(Qmin-Qmax)*Math.random();
		  for(int j=0;j<d;j++)
		  {v[i][j]=v[i][j]+((Sol[i][j]-best[j])*Q[i]);
		   S[i][j]=Sol[i][j]+v[i][j]; 
		  }	
		  Sol[i]=simplebounds(Sol[i]);
		  //System.out.println(Matrix.toString(Sol[i]));	
		  if(Math.random()>r)
		  {for(int j=0;j<d;j++)
		   {S[i][j]=best[j]+(0.001*rndm.nextGaussian());}
		  }	
		  fnew=ff.func(S[i]);
		  
		  if((fnew<=fitness[i])&&(Math.random()<A))
		  { for(int j=0;j<d;j++)
			 {Sol[i][j]=S[i][j];}
		      fitness[i]=fnew;
		  }
		  
		  if(fnew<=fmin)
		  {for(int j=0;j<d;j++)
		   {best[j]=S[i][j];}
		    fmin=fnew;}	
		}  
		t++;
	}	 
		System.out.println("Optimum value = "+fmin);
		for(int i=0;i<d;i++)
		{System.out.println("x["+i+"] = "+best[i]);}
	}
}