/////////////////////////////////////////////////////////////////////////////////
//  Referance paper                                                            //
//  Bahriye Akay , Dervis Karaboga, A modified Artificial Bee Colony algorithm //
//  for real-parameter optimization                                            //
//  http://mf.erciyes.edu.tr/abc/                                              //
//  Matlab codes are translated into Java codes                                //
//  Programmer: Ošuz Emrah Turgut                                              //
/////////////////////////////////////////////////////////////////////////////////
 
abstract class f_xj
{
abstract double func(double x[]);
}

public class artificial_bee_colony
{
int D;//Number of optimized parameter	
int N;//Colony size(employed + onlooker bee)
int FS;//Number of food sources
int limit;//Limited food source number
int Cyclemax;//Maximum number of Cycles
double Foods[][];
double Fitness[];
double Objval[];
int trial[];
double prob[];
double xmin[];
double xmax[];
double sol[];
double Objvalsol;
int randomjj;//param2change
int randomkk;//neighbourhood
double FitnessSol;
double Globalmin;
double GlobalParams[];
double fmin;
int indexfmin;
double phi;
f_xj ff;

      public artificial_bee_colony(f_xj iff,int iN,int ilimit,int iCyclemax,double ixmin[],double ixmax[])
      {
	  ff=iff;    
	  D=ixmin.length;   
	  N=iN;  
	  FS=N/2;
	  limit=ilimit;   
	  Cyclemax=iCyclemax; 
	  xmin=new double[D];
	  xmax=new double[D];
	  sol=new double[D];
	  Foods=new double[FS][D];
	  Objval=new double[FS];    
	  Fitness=new double[FS];  
	  trial=new int[FS];    
	  prob=new double[FS];
	  GlobalParams=new double[D];
	  for(int i=0;i<D;i++)
	  {xmin[i]=ixmin[i];xmax[i]=ixmax[i];}
	  }
      
	  
	  //Initializing food resources,fitness values, global optimum parameters 
      void initialize()
      {
	  for(int i=0;i<FS;i++)
	  {for(int j=0;j<D;j++)
	   {Foods[i][j]=xmin[j]+((xmax[j]-xmin[j])*Math.random());}
	   Objval[i]=ff.func(Foods[i]);}
	   Fitness=Fitcalc(Objval);	      
	   double[] dep=getminval_index(Objval);   
	   fmin=dep[0];
	   indexfmin=(int)(dep[1]);  
	   Globalmin=Objval[indexfmin];
	   for(int i=0;i<D;i++)
	   {GlobalParams[i]=Foods[indexfmin][i];}
	  }

	  // returns minimum value and its index in an array
     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;	 
	 } 
	   // returns maximum value index of an array
	 int getmaxval_index(int a[])
	 {
	 int m=0;
	 double b[]=new double[a.length];
	 for(int i=0;i<a.length;i++)
	 {b[i]=a[i];}
	 double maxval=a[0];
	 for(int j=0;j<a.length;j++)
	 {if(maxval>a[j]){maxval=a[j];}}
	 for(int i=0;i<b.length;i++)
	 {if(b[i]==maxval){m=i;break;}}
	 return m;	 
	 }

	 
      //fitness manipulation of an array
	 double[] Fitcalc(double a[])
	 {
	 double[] out=new double[FS];	 
	 for(int i=0;i<FS;i++)
	 { if(a[i]>=0.0)
	   {out[i]=1.0/(1.0+a[i]);}
	   else
	   {out[i]=1.0+Math.abs(a[i]);}
	 }	 
	 return out;	 
	 }
	 // fitness manipulation of double value (Equation 3)
	 double Fitcalc(double aa)
	 {
	 double out=0.0;
	 if(aa>=0.0)
	 {out=1.0/(1.0+aa);}
	 else{out=1.0+Math.abs(aa);}
	 return out;	 
	 }
     //Boundary correction
	 double[] simpleboundss(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();// initializing parameters
		int iter=1;		
		while(iter<=Cyclemax) //iteration starts
		{
		iter++;	
		//EMPLOYED BEE PHASE 
		for(int i=0;i<FS;i++)
		{
			randomjj=(int)Math.floor(D*Math.random());//creates random integer that is element of [0,D] 
			randomkk=(int)Math.floor(FS*Math.random());//creates random integer that is element of [0,FS] 
			phi=2.0*(Math.random()-0.5);//creates Random number that is element of [-1,1];
			while(randomkk==i)//randomkk values must be different from i
			{randomkk=(int)Math.floor(FS*Math.random());}
			for(int j=0;j<D;j++)
			{sol[j]=Foods[i][j];}
			//v[i][j]=x[i][j]+phi[i][j]*(x[i][j]-x[k][j]);    equation (2)
			sol[randomjj]=Foods[i][randomjj]+((Foods[i][randomjj]-Foods[randomkk][randomjj])*phi);
			sol=simpleboundss(sol);
			
			Objvalsol=ff.func(sol);
	        FitnessSol=Fitcalc(Objvalsol); 		
			if(FitnessSol>Fitness[i])
			{for(int j=0;j<D;j++){Foods[i][j]=sol[j];}	
			 Fitness[i]=FitnessSol;	
			 Objval[i]=Objvalsol;	
			 trial[i]=0;
		    }else{trial[i]++;}
		} 		 
		//Probability value calculation (Equation 4)
		for(int i=0;i<FS;i++)
		{double sum=0.0;
		 for(int k=0;k<FS;k++)
		 {sum+=Fitness[k];}
		 prob[i]=Fitness[i]/sum; 
	    }	    
		/////// ONLOOKER BEE PHASE ///////////// 
	    int ii=0;
	    int tt=0;
	    while(tt<FS)
		{
		  if(Math.random()<prob[ii])
		  {
		  	  
			  tt++;    
			  randomjj=(int)Math.floor(D*Math.random());//creates random number that is element of [0,D] 
			  randomkk=(int)Math.floor(FS*Math.random());//creates random number that is element of [0,FS] 
			  phi=2.0*(Math.random()-0.5);//creates Random number that is element of [-1,1];
			  while(randomkk==ii)
			  {randomkk=(int)Math.floor(FS*Math.random());}
			  for(int j=0;j<D;j++)
			  {sol[j]=Foods[ii][j];}
			  sol[randomjj]=Foods[ii][randomjj]+((Foods[ii][randomjj]-Foods[randomkk][randomjj])*phi);
			  sol=simpleboundss(sol);
			  Objvalsol=ff.func(sol);
	          FitnessSol=Fitcalc(Objvalsol); 		
			  //Greedy selection is applied between  the current solution ii and its mutant
	          if(FitnessSol>Fitness[ii])
			  {for(int j=0;j<D;j++){Foods[ii][j]=sol[j];}	
			  Fitness[ii]=FitnessSol;	
			  Objval[ii]=Objvalsol;	
			  trial[ii]=0;
		      }else{trial[ii]++;}// if not improve , increase trial
		      
		  }
			   ii++;
			   if(ii==(FS))
			   {ii=0;}
			   
        }	
			
        //The best(food source) will remain, others will be changed
			double[] dep=getminval_index(Objval);
			double fminn=dep[0];
			int index=(int)dep[1];
			if(Objval[index]<Globalmin)
			{Globalmin=Objval[index];
			for(int j=0;j<D;j++)
			{GlobalParams[j]=Foods[index][j];}}
			
			
		// SCOUT BEE PHASE
		   int ind=getmaxval_index(trial);
		   	
		   if(trial[ind]>limit)
		   {
		   	trial[ind]=0;
		   	for(int j=0;j<D;j++)
		   	{sol[j]=xmin[j]+((xmax[j]-xmin[j])*Math.random());}   
			Objvalsol=ff.func(sol);   
			FitnessSol=Fitcalc(Objvalsol); 
			for(int i=0;i<D;i++)
			{Foods[ind][i]=sol[i];}
			Fitness[ind]=FitnessSol;
			Objval[ind]=Objvalsol;
		   }	
		
		}
		System.out.println("Optimized value = "+Globalmin);
		for(int i=0;i<D;i++)
		{System.out.println("x["+i+"] = "+GlobalParams[i]);}	
	 } 
}
	 
	 
	 
	 
	 
	  
	 
	 
	 
	 




