///////////////////////////////////////////////////////////////////////////////////////////////////////////
/// Hybrid search = Particle Swarm Optimization+Artificial bee colony + Harmony search ////////////////////
///////////////////////////////////////////////////////////////////////////////////////////////////////////
//Hybrid harmony search and artificial bee colony algorithm for global optimization problems
//Bin Wu., Cunhua Qian, Weihong Ni, Shuhai Fan 
// Nanjing University of Technology,Department of Industrial Engineering
///////////////////////////////////////////////////////////////////////////////////////////////////////////
import java.util.Vector;
import java.util.Arrays;
import java.util.Collections;
import java.util.Comparator;
import java.io.*;
import java.lang.Double;



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


public class hybrid_search2
{
	
int D;	
int N;// Colony size(employed + onlooker bee)
int FS;// Number of food source 
int limit;//Limited food source number
int Cyclemax;//Maximum number of Cycles
double Lower[];//Lower bound
double Upper[];//Upper bound
double HMCR; //Harmony consideration rate
double PAR; //Pitch adjustment rate
double PARmax;
double PARmin;
double minval;
int mindex;
double maxval;
int maxdex;
double Xnew[];//new vector for harmony search
double best[];
double worst[];
double fitness[];
int iter;
double prob[];// probability vector for roulette selection
int trial[];
double X[][];
double V[][];
int randj;
int randindex;
int L;
f_xj ff;
double w;
double c1;
double c2;

     public hybrid_search2(f_xj iff,int iN,int ilimit,int iCyclemax,double iLower[],double[] iUpper,double iHMCR,double iw,double ic1,double ic2)
     {
	 ff=iff;  
	 N=iN;    
	 FS=N/2;
	 Lower=iLower;    
	 Upper=iUpper;
	 D=Lower.length;  
	 limit=ilimit;    
	 Cyclemax=iCyclemax;
	 HMCR=iHMCR;
	 PARmax=2.0;
	 PARmin=0.0;
	 X=new double[FS][D];
	 V=new double[FS][D];
	 best=new double[D];
	 worst=new double[D];
	 Xnew=new double[D];
	 trial=new int[FS];
	 prob=new double[FS];
	 fitness=new double[FS];
	 w=iw;
	 c1=ic1;
	 c2=ic2;
	 }

	 void initialize()
	 {
		for(int i=0;i<FS;i++)
		{
		   for(int j=0;j<D;j++)
		   {
		    X[i][j]=Lower[j]+(Math.random()*(Upper[j]-Lower[j]));	   
		   }  	  
		}
		
		
	    for(int i=0;i<FS;i++)
	    {fitness[i]=ff.func(X[i]);}	
		double[] d1=getminval_index(fitness);
		minval=d1[0];
		mindex=(int)d1[1];
		for(int i=0;i<D;i++)
		{best[i]=X[mindex][i];}
		
		double d2[]=getmaxval_index(fitness);
		maxval=d2[0];
		maxdex=(int)d2[1];
		for(int i=0;i<D;i++)
		{worst[i]=X[maxdex][i];}
		
     }
     
     
     
     
	 double[][] bounds(double x[][])
	 {
	 int n=x.length;	 
	 for(int i=0;i<FS;i++)
	    {for(int j=0;j<D;j++)
	    {if((x[i][j]<Lower[j])||(x[i][j]>Upper[j]))
        {x[i][j]=Lower[j]+(Math.random()*(Upper[j]-Lower[j]));}}}	 
	 return x;      	 
	 }
	 
	 
	 double[] roulette_selection(double x[]) 
	 {
	 int n=x.length;double s1=0.0;	 
	 for(int i=0;i<n;i++)
	 {s1+=x[i];}
	 double[] out=new double[FS];
	 for(int i=0;i<FS;i++)
	 {out[i]=x[i]/s1;}
	 return out;
	 }
	 
	 
	 
	 double[][] solution()
     {
	   initialize();
	     
	   iter=1;  
	   while(iter<Cyclemax)  
	   {
		  for(int i=0;i<FS;i++)
		  {
		  randj=(int)Math.floor(D*Math.random());
		  randindex=(int)Math.floor(FS*Math.random()); 	  
		  while(randindex==i)
		  {randindex=(int)Math.floor(FS*Math.random());}
		  
		  for(int j=0;j<D;j++)
		  {V[i][j]=X[i][j];} 	  
		  
		  V[i][randj]=(w*X[i][randj])+c2*(((Math.random()-0.5)*2.0)*(X[randindex][randj]-X[i][randj]))+(c1*((Math.random()-0.5)*2.0)*(best[randj]-X[i][randj]));
		  V=bounds(V);
		  
		  if(ff.func(V[i])<ff.func(X[i]))
		  {
		  trial[i]=0;
		  for(int j=0;j<D;j++)
		  {X[i][j]=V[i][j];}	  
		  }	  
		  else
		  {
		  trial[i]++;	  
		  }
	      }
		  
		  for(int i=0;i<FS;i++)
		  {fitness[i]=ff.func(X[i]);}
		  prob=roulette_selection(fitness);
		  
		  
		  int tt=0;
		  int ii=0;
		  while(tt<FS)
		  {
		    if(Math.random()<prob[ii])	  
			{
			tt++;	
			randj=(int)Math.floor(D*Math.random());  
			randindex=(int)Math.floor(FS*Math.random());
			  while(randindex==ii)
			  {randindex=(int)Math.floor(FS*Math.random());}	
			  for(int j=0;j<D;j++)
			  {V[ii][j]=X[ii][j];} 	
			   V[ii][randj]=(w*X[ii][randj])+c2*(((Math.random()-0.5)*2.0)*(X[randindex][randj]-X[ii][randj]))+(c1*((Math.random()-0.5)*2.0)*(best[randj]-X[ii][randj]));
			  if(ff.func(V[ii])>ff.func(X[ii]))
			  {
			  trial[ii]=0;
			  for(int j=0;j<D;j++)
			  {X[ii][j]=V[ii][j];}	  
			  }	
			  else
			  {
			  trial[ii]++;	  
			  }	
            }
            ii++;
            if(ii==(FS))
			{ii=0;}   
		  }
		  
		  	  
		  for(int i=0;i<FS;i++)
		  {
		    if(trial[i]>limit)
			{
		      for(int j=0;j<D;j++)
		      {X[i][j]=Lower[j]+(Math.random()*(Upper[j]-Lower[j]));}
						
		    }  	  
		  }
		  
		  
		  for(int j=0;j<D;j++)
		  {
			  if(Math.random()<HMCR)
			  {
			  L=(int)(((double)FS)*Math.random());			             
		      PAR=PARmax-((PARmax-PARmin)*((double)iter)/((double)Cyclemax));  	  
			  Xnew[j]=X[L][j]+Math.random()*((Lower[j]-Upper[j])/100.0);
			     
		            if(Math.random()<PAR)
		            {Xnew[j]=best[j];}
			  
			  }
              else
              {
	          Xnew[j]=Lower[j]+(Math.random()*(Upper[j]-Lower[j]));    
	          }			 
		 }
		  
		 if(ff.func(Xnew)>ff.func(worst))
		 {
		   for(int j=0;j<D;j++)
		   {worst[j]=Xnew[j];}	 
		 }
		 
		 for(int i=0;i<FS;i++)
		 {fitness[i]=ff.func(X[i]);} 
		  
		 double[] dd4=getminval_index(fitness);
		 minval=dd4[0];
		 mindex=(int)dd4[1];
		 for(int i=0;i<D;i++)
		 {best[i]=X[mindex][i];}
		 
		 double[] dd5=getmaxval_index(fitness);
         maxval=dd5[0];
		 maxdex=(int)dd5[1];
		 for(int i=0;i<D;i++)
		 {X[maxdex][i]=worst[i];} 
		 
		 iter++;
		 } 
		
		 double[][] dp=new double[2][D];
		 dp[0][0]=minval;
		 for(int i=0;i<D;i++)
		 {dp[1][i]=best[i];}
		 return dp;  
		}  
	     
		void toStringnew()
		{
			double out[][]=solution();
			System.out.println("Optimized value = "+out[0][0]);
			for(int i=0;i<D;i++)
			{System.out.println("x["+i+"] = "+out[1][i]);}
			
			
	    }
		
	     
	     
	 double[] getmaxval_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 maxval=a[0];
	 for(int j=0;j<a.length;j++)
	 {if(a[j]>maxval){maxval=a[j];}}
	 for(int i=0;i<b.length;i++)
	 {if(b[i]==maxval){m=i;break;}}
	 double dep2[]=new double[2];
	 dep2[0]=maxval;
	 dep2[1]=m;
	 return dep2;	 
	 }
     
	 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;	 
	 }
	 
	 void toTxtfile()
		{   
			String line="";
			int lineNo;
			try
			   {
			   FileWriter fw=new FileWriter("hybridsearch2_f77.txt",true); 	   
			   BufferedWriter bw=new BufferedWriter(fw);
			   LineNumberReader lnr=new LineNumberReader(new FileReader("hybridsearch2_f77.txt"));   
			   lnr.setLineNumber(1);
			   for(int i=1;i<=lnr.getLineNumber();i++)
			   {bw.newLine();}
			   double[][] dd=solution();
			   Double d1d=new Double(dd[0][0]);
			   String s1=d1d.toString();
			   int nn=dd[1].length;
			   Double[] val=new Double[nn];
			   String[] str=new String[nn];
			   for(int i=0;i<nn;i++)
			   {val[i]=new Double(dd[1][i]);}
			   for(int i=0;i<nn;i++)
			   {str[i]=val[i].toString();}
			   bw.write(s1+" ");
			   for(int i=0;i<nn;i++)
			   {bw.write(str[i]+" ");}
			   bw.close();
			   lnr.close();
		       }catch(IOException e)
		       {e.printStackTrace();}
			   
		}
	 
	 
	 
	 
	 
}












