import java.util.Random;


///////////////////////////////////////////////////////////////////////////////
/// Simulated Annealing (by X-S Yang, Cambridge University)
///REFERANCE---> Engineering Optimization : An introduction with Metaheuristic Applications 
///////////////////////////////////////////////////////////////////////////////
abstract class f_xj
{
abstract double func(double x[]);
}

public class simulated_annealing
{
double Tinit;
double Tmin;
double Fmin;
int maxrej;
int maxruns;
int maxaccept;
double k;
double alpha;
double enorm;
double guess[];
double best[];
int dimen;
f_xj ff;


         public simulated_annealing(f_xj iff,double iTinit,double iTmin,double iFmin,int imaxrej,int imaxruns,int imaxaccept,double ik,double ialpha,double ienorm,int idimen)
         {
	     Tinit=iTinit;
	     Tmin=iTmin;
	     Fmin=iFmin;
	     maxrej=imaxrej;    
	     maxruns=imaxruns;
	     maxaccept=imaxaccept;    
	     k=ik;
	     alpha=ialpha;    
	     enorm=ienorm;
	     dimen=idimen;
	     ff=iff;
	     guess=new double[dimen];
	     best=new double[dimen];
	     for(int i=0;i<dimen;i++)
	     {guess[i]=2.0;}    
	     }
	
          
	     

	     void solution()
	     {
		  System.out.println("This may take a few seconds...");    
		  int i=0;int j=0;int accept=0;int totaleval=0;
		  double T=Tinit;
		  double Einit=ff.func(guess); 
		  double Eold=Einit;
		  double Enew=Eold;
		  for(int tt=0;tt<dimen;tt++)
		  {best[tt]=guess[tt];}
		
		  double deltaE=0.0;
		  double fopt=0.0;
		  double[] ns=new double[dimen];
		  Random rndm=new Random();
		  while((T>Tmin)&&(j<=maxrej)&&(Enew>Fmin))
		  {
		   i++;
		   if((i>=maxruns)||(accept>=maxaccept))
		   {
		   T=alpha*T;
		   totaleval+=i;
		   i=1;;accept=1;	   
		   }
		   //System.out.println(Matrix.toString(best)); 
		   for(int jj=0;jj<dimen;jj++)
		   {ns[jj]=guess[jj]+(Math.random()*rndm.nextGaussian());}
		   Enew=ff.func(ns);	  
		   deltaE=Enew-Eold;
		   if(-deltaE>enorm)
		   {
		   for(int jj=0;jj<dimen;jj++)
		   {best[jj]=ns[jj];}
		   Eold=Enew;
		   accept++;j=0; 	   
		   }
		   if((deltaE<=enorm)&&(Math.exp(-deltaE/(k*T))>Math.random()))
		   {
		   for(int jj=0;jj<dimen;jj++)
		   {best[jj]=ns[jj];}
		   Eold=Enew;
		   accept++;j=0;   
		   }else{j++;}	  
		   fopt=Eold;  
		  }  
		   
		   System.out.println("Optimized value = "+fopt);
		   for(int ii=0;ii<dimen;ii++)
		   {System.out.println("x["+ii+"]="+best[ii]);}   
		    
		     
		     
		 }

         











}