//////////////////////////////////////////////////////////////////
//Referans ------- Transforming geocentric cartesian coordinates//
//to geodetic coordinates by using differential search algorithm//  
//////////////////////////////////////////////////////////////////
//Programlayan -- Ošuz Emrah Turgut  /////////////////////////////
//////////////////////////////////////////////////////////////////

import java.util.Random;
import java.io.*;
abstract class f_xj
{
abstract double func(double x[]);
}

public class differential_search
{
int maxiter;
int N;
int D;
double Globalminimum;
double[] Globalminimizer;
double[] Lower;
double[] Upper;
double[] BEST;
double Scale;
double[][] r;
double[][] Superorganism;
double[][] Stopoversite;
double[] yStopoversite;
double[] ySuperorganism;
double[][] donor;
double[] y;
double p1;
double p2;  
double fitnessbest;
f_xj ff;


public differential_search(f_xj iff,int iN,double[] iLower,double[] iUpper,int imaxiter)
{
maxiter=imaxiter;
ff=iff;
N=iN;
Lower=iLower;
Upper=iUpper;
D=Lower.length;	
Superorganism=new double[N][D];	
Stopoversite=new double[N][D];	
donor=new double[N][D];	
r=new double[N][D];	
y=new double[N];
Globalminimizer=new double[D];
BEST=new double[maxiter];
yStopoversite=new double[N];
ySuperorganism=new double[N];
Globalminimum=1e10;
	
}

void initialize()
{
  for(int i=0;i<N;i++)
  {for(int j=0;j<D;j++)
    {Superorganism[i][j]=Lower[j]+((Upper[j]-Lower[j])*Math.random());}}	
  for(int i=0;i<N;i++)
  {ySuperorganism[i]=ff.func(Superorganism[i]);}
 
}

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;	 
}

// Random permutation of matrix
double[][] randperm(double a[][])
{
double y[][]=new double[a.length][a[0].length];
double[] sw=new double[a[0].length];
for(int i=0;i<a.length;i++)
{y[i]=a[i];}
int m=a.length;
int rp=0;
for(int i=0;i<m-1;i++)
{rp=(int)((m-i)*Math.random()+i);sw=y[i];
y[i]=y[rp];y[rp]=sw;}
return y;	 
}

int randi(int up)
{return (int)Math.floor(up*Math.random());}

int[] randi(int up,int count)
{   
   int[] aa=new int[count]; 	
   for(int i=0;i<count;i++)
   {aa[i]=(int)Math.floor(up*Math.random());}
 return aa; 		
}

double[][] solution()
{
initialize();
int dd[];
int mindex;
int iter=0;

   while(iter<maxiter)
   {
    donor=randperm(Superorganism);	
	
	p1=0.3*Math.random();
	p2=0.3*Math.random();
	    if(Math.random()<Math.random())
	    {
		      if(Math.random()<p1)
		      { // Random-mutation I strategy
			    for(int i=0;i<N;i++)
			    {for(int j=0;j<D;j++)
				  {if(Math.random()<Math.random())
					{r[i][j]=1.0;}}}
		      }		
			  else
			  { // Diferential mutation strategy
			     for(int i=0;i<N;i++)
			     {r[i][randi(D)]=1.0;} 	   
			  }		
		}
	    else
	    {
		       // Random-mutation II strategy 
		       for(int i=0;i<N;i++)
		       {dd=randi(D,(int)(p2*D));
			      for(int j=0;j<dd.length;j++)
			      {r[i][dd[j]]=1.0;}}     
		}
	
		Random rndm=new Random();
	    Scale=4.0*(rndm.nextGaussian());// brownian walk
	    // bio-interaction
	    for(int i=0;i<N;i++)
	     {for(int j=0;j<D;j++)
	      {Stopoversite[i][j]=Superorganism[i][j]+((Scale*r[i][j])*(donor[i][j]-Superorganism[i][j]));}}
	   
	    // Boundary control;
	    for(int i=0;i<N;i++)
	    {for(int j=0;j<D;j++)
		  {if((Stopoversite[i][j]<Lower[j])||(Stopoversite[i][j]>Upper[j]))
		    {Stopoversite[i][j]=Lower[j]+(Math.random()*(Upper[j]-Lower[j]));}}}
		
		// Selection II
		for(int i=0;i<N;i++)
		{yStopoversite[i]=ff.func(Stopoversite[i]);}
		
		for(int i=0;i<N;i++)
		{
		  if(yStopoversite[i]<ySuperorganism[i])
		  {ySuperorganism[i]=yStopoversite[i];
		    for(int j=0;j<D;j++)
		    {Superorganism[i][j]=Stopoversite[i][j];}}
		}     
	 
		double x1[]=getminval_index(ySuperorganism);
		fitnessbest=x1[0];
		mindex=(int)x1[1];
		
		if (fitnessbest<Globalminimum)
	    {
		     Globalminimum=fitnessbest;
	         for(int j=0;j<D;j++)
	         {Globalminimizer[j]=Superorganism[mindex][j];}
	    }
	     BEST[iter]=Globalminimum;
		iter++;
   }	
	        double[] plott=new double[maxiter];
		    for(int i=0;i<maxiter;i++)
		    {plott[i]=i;}
		    Plot pp=new Plot(plott,BEST);
		    //pp.plot();
      double out[][]=new double[2][Globalminimizer.length];
	  out[0][0]=Globalminimum;out[0][1]=Globalminimizer.length;
	  for(int i=0;i<Globalminimizer.length;i++)
	  {out[1][i]=Globalminimizer[i];}
	  return out;
	
}

void toStringnew_constf16()
{
double[][] out=solution();
System.out.println("Optimized value = "+out[0][0]);
for(int i=0;i<out[0][1];i++)
{System.out.println("x["+i+"] = "+out[1][i]);}
double x[]=new double[(int)out[0][1]];
for(int i=0;i<(int)out[0][1];i++)
{x[i]=out[1][i];}
double fx=x[0]+x[1]+x[2];
double h1=-1.0+0.0025*(x[3]+x[5]);
double h2= -1.0+0.0025*(x[4]+x[6]-x[3])  ;
double h3=-1.0+0.01*(x[7]-x[4]);
double h4=-x[0]*x[5]+833.33252*x[3]+100.0*x[0]-83333.333;
double h5=-x[1]*x[6]+1250.0*x[4]+x[1]*x[3]-1250.0*x[3] ;
double h6=-x[2]*x[7]+1250000.0+x[2]*x[4]-2500.0*x[4] ;

System.out.println("fx = "+fx);
System.out.println("h1 = "+h1);
System.out.println("h2 = "+h2);
System.out.println("h3 = "+h3);
System.out.println("h4 = "+h4);
System.out.println("h5 = "+h5);
System.out.println("h6 = "+h6);
System.out.println("*******************************");
}

void toStringnew()
{
double[][] out=solution();
System.out.println("Optimized value = "+out[0][0]);
for(int i=0;i<out[0][1];i++)
{System.out.println("x["+i+"] = "+out[1][i]);}
}

void toStringnew_constf4()
{
double[][] out=solution();
System.out.println("Optimized value = "+out[0][0]);
for(int i=0;i<out[0][1];i++)
{System.out.println("x["+i+"] = "+out[1][i]);}
double x[]=new double[(int)out[0][1]];
for(int i=0;i<(int)out[0][1];i++)
{x[i]=out[1][i];}

double fx=(0.6224*x[0]*x[2]*x[3])+(1.7781*x[1]*x[2]*x[2])+(3.1661*x[0]*x[0]*x[3])+(19.84*x[0]*x[0]*x[2]);
double h1=-x[0]+0.0193*x[2];
double h2=-x[1]+0.00954*x[2];
double h3=-Math.PI*x[2]*x[2]*x[3]-(4.0/3.0)*3.1415*x[2]*x[2]*x[2]+1296000;
double h4=x[3]-240.0;


System.out.println("fx ="+fx);
System.out.println("h1 ="+h1);
System.out.println("h2 ="+h2);
System.out.println("h3 ="+h3);
System.out.println("h4 ="+h4);


System.out.println("*******************************");
}

// speed reducer
void toStringnew_constf5()
{
double[][] out=solution();
System.out.println("Optimized value = "+out[0][0]);
for(int i=0;i<out[0][1];i++)
{System.out.println("x["+i+"] = "+out[1][i]);}
double x[]=new double[(int)out[0][1]];
for(int i=0;i<(int)out[0][1];i++)
{x[i]=out[1][i];}

double fx=0.7854*x[0]*x[1]*x[1]*(3.3333*x[2]*x[2]+14.9334*x[2]-43.0934)-(1.508*x[0]*(x[5]*x[5]+x[6]*x[6]))+(7.4777*(x[5]*x[5]*x[5]+x[6]*x[6]*x[6]))+(0.7854*(x[3]*x[5]*x[5]+x[4]*x[6]*x[6]));
double h1=(27.0/(x[0]*x[1]*x[1]*x[2]))-1.0 ;
double h2=(397.5/(x[0]*x[1]*x[1]*x[2]*x[2]))-1.0;
double h3=((1.93*x[3]*x[3]*x[3])/(x[1]*x[5]*x[5]*x[5]*x[5]*x[2]))-1.0 ;
double h4=((1.93*x[4]*x[4]*x[4])/(x[1]*x[6]*x[6]*x[6]*x[6]*x[2]))-1.0 ;
double h5=(Math.sqrt((745.0*(x[3]/(x[1]*x[2])))*(745.0*(x[3]/(x[1]*x[2])))+16.9e6)/(110.0*x[5]*x[5]*x[5]))-1.0   ;
double h6=(Math.sqrt((745.0*(x[4]/(x[1]*x[2])))*(745.0*(x[3]/(x[1]*x[2])))+157.5e6)/(85.0*x[6]*x[6]*x[6]))-1.0 ;
double h7=(x[1]*x[2]/40.0)-1.0   ;
double h8=(5.0*x[1]/x[0])-1.0  ;
double h9=(x[0]/(12.0*x[1]))-1.0 ;
double h10=((1.5*x[5]+1.9)/x[3])-1.0 ;
double h11=((1.1*x[6]+1.9)/x[4])-1.0;



System.out.println("fx ="+fx);
System.out.println("h1 ="+h1);
System.out.println("h2 ="+h2);
System.out.println("h3 ="+h3);
System.out.println("h4 ="+h4);
System.out.println("h5 ="+h5);
System.out.println("h6 ="+h6);
System.out.println("h7 ="+h7);
System.out.println("h8 ="+h8);
System.out.println("h9 ="+h9);
System.out.println("h10 ="+h10);
System.out.println("h11 ="+h11);


System.out.println("*******************************");
}


void toTxtfile()
		{   String named="diffsearch_f31_sphere50.txt";
			String line="";
			int lineNo;
			try
			   {
			   FileWriter fw=new FileWriter(named,true); 	   
			   BufferedWriter bw=new BufferedWriter(fw);
			   LineNumberReader lnr=new LineNumberReader(new FileReader(named));   
			   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();}
			   
		}		 



}