import java.util.Random;
import java.io.*;
///////////////////////////////////////////////////
///A new optimization method: Big Bang–Big Crunch//
///////////////////////////////////////////////////
//Osman K. Erol*, Ibrahim Eksin////////////////////
///////////////////////////////////////////////////

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

public class big_bang_big_crunch
{

int N;
int maxiter;
int D;
double Lower[];
double Upper[];
double X[][];
double fitness[];
double Xcenter[];
double best[];
double worst[];
double Xnew[];
int iter;
double beta;
double alfa;
double minval;
double maxval;
int mindex;
int maxdex;
f_xj ff;

       public big_bang_big_crunch(f_xj iff,int iN,int imaxiter,double[] iLower,double[] iUpper,double ibeta,double ialfa)
       {
	   ff=iff;  
	   N=iN;
	   maxiter=imaxiter;
	   Lower=iLower;    
	   Upper=iUpper;
	   beta=ibeta;
	   alfa=ialfa;
	   D=Lower.length;
	   Xnew=new double[D];
	   X=new double[N][D];  
	   fitness=new double[N];   
	   best=new double[D];
	   worst=new double[D];
	   Xcenter=new double[D];
	   }

       void initialize()
       {
	    for(int i=0;i<N;i++)
	    {for(int j=0;j<D;j++)    
		    {X[i][j]=Lower[j]+((Upper[j]-Lower[j])*Math.random());}}    
	   
		    for(int i=0;i<N;i++)
		    {fitness[i]=ff.func(X[i]);}  
		    
		    double dd[]=getminval_index(fitness);
		    minval=dd[0];
		    mindex=(int)dd[1];
		    for(int i=0;i<D;i++)
		    {best[i]=X[mindex][i];}
		    
		    
		    double dd1[]=getmaxval_index(fitness);
		    maxval=dd1[0];
		    maxdex=(int)dd1[1];
		    for(int i=0;i<D;i++)
		    {worst[i]=X[maxdex][i];}
	   }
	   
	   
	   
	   double[] simplebounds(double s[])
	   {
	   for(int i=0;i<D;i++)
	   {if(s[i]<Lower[i])
	    {s[i]=Lower[i];}
	    if(s[i]>Upper[i])
	    {s[i]=Upper[i];}
	   }	 
	   return s;	 
	   }
	   
	 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[] 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[][] solution()
	 {
		initialize();
		iter=1;
		Random rnd=new Random();
		while(iter<maxiter) 
		{   
		   double dd3[]=getminval_index(fitness);
		   mindex=(int)dd3[1];   
		   for(int i=0;i<D;i++)
		   {Xcenter[i]=X[mindex][i];}
		   
		   for(int i=0;i<D;i++)
		   {Xnew[i]=(beta*Xcenter[i])+((1.0-beta)*best[i])+(rnd.nextGaussian()*((Upper[i]-Lower[i])/(double)iter));}
		   
		   Xnew=simplebounds(Xnew);
		   
		   if(ff.func(Xnew)<ff.func(worst))
		   {
		      for(int i=0;i<D;i++)
		      {worst[i]=Xnew[i];}
		   }
		   
		   for(int i=0;i<N;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)dd4[1]; 
		   	for(int i=0;i<D;i++)
		   	{X[maxdex][i]=worst[i];}
	        iter++;
	     }  
	     //System.out.println(Matrix.toString(best));
	     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]);}  
	   }
	   
	   void toTxtfile()
		{   
			String line="";
			int lineNo;
			try
			   {
			   FileWriter fw=new FileWriter("bigbang_gibbs6.txt",true); 	   
			   BufferedWriter bw=new BufferedWriter(fw);
			   LineNumberReader lnr=new LineNumberReader(new FileReader("bigbang_gibbs6.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();}
			   
		}
	   
	   
	   
}