import java.io.*;
import java.text.*;
import java.util.Locale;
import java.io.*;
import javax.swing.JOptionPane;

abstract class f_xj
{ 
  // single function  multi independent variable
  // a single value is returned  (
  // example f=x[0]+sin(x[1])
  // func(x) returns the value of f
  abstract public double func(double x[]);
}

class fa extends f_xj
{
//çözümü istenen fonksiyon	
 public double func(double x[])
 {
    double ff= -(x[0]-2.0)*(x[0]-2.0)+(x[1]-3.0)*(x[1]-3.0);
    return ff; 
}
}

public class SAn
{
    public static double[] simulatedannealing(f_xj f,double xmin[],double xmax[],double Ti)
    {
	    
	double k=1;
	double k0=k;
	double T=20.0; 
	double T0=Ti;   
	int n=xmin.length;    
	double x[]=new double[n];
	double x1[]=new double[n];
	double dx[]=new double[n];
	double best[]=new double[n];
	double fbest=0;
	//randomly select first point
	int maxit=100;
	int mi=0;
	double pdf=0;
	double ff,f1;
	while(mi<maxit)
	{
	for(int i=0;i<n;i++)
	{ x[i]=xmin[i]+(xmax[i]-xmin[i])*Math.random();if(mi==0) best[i]=x[i];fbest=f.func(best);}
	ff=f.func(x);
	System.out.println("f="+ff);
    int successfulliteration=5;
    int it=0;
    while(it<successfulliteration)
    {
	for(int i=0;i<n;i++)
	{ dx[i]=gaussrandom()*T;x1[i]=x[i]+dx[i];while((x1[i]<xmin[i] || x1[i]>xmax[i])){dx[i]=gaussrandom()*T;x1[i]=x[i]+dx[i];}}
    double z=1/(k*T)*Math.random();	
    f1=f.func(x1);
    if(f1<fbest) {fbest=f1;best=x1;}
    System.out.println("f1="+f1);
    double df=f1-ff;
    pdf=1/(k*T)*Math.exp(-df/(k*T));
    if(df<0) {x=x1;it++;ff=f.func(x);System.out.println("it="+it+"f="+ff+"df="+df);}
    else if(pdf>z) {x=x1;it++;ff=f.func(x);System.out.println("it="+it+"f="+ff+"df="+df+"pdf="+pdf);}
	}
	k++;
    //double lk=Math.log(k);
    //T=T-Math.log(k0)/(k*lk*lk);
    T=T0/(1+k);
    System.out.println("k="+k+"T="+T+"pdf="+pdf+"f="+ff);
	mi++;
    }
    return best;
    }
    
	
    public static double  gaussrandom()
    { int iset=0;
    double gset=0;
    double fac,rsq,v1,v2;
    double aret=0;
    if(iset==0)
    {
     do{
	 v1=2.0*Math.random()-1.0;
	 v2=2.0*Math.random()-1.0;
	 rsq=v1*v1+v2*v2;  
     }while(rsq>=1.0 || rsq==0.0);	   
    fac=Math.sqrt(-2.0*Math.log(rsq)/rsq);
    gset=v1*fac;
    iset=1;
    aret=v2*fac;
    }
    else
    {
    iset=0;
    aret=gset;
    }
    return aret;	
    }

    public static void main(String args[]) throws IOException
    {
	double low[]=new double[2];
	double high[]=new double[2];
    low[0]=-10.0;high[0]=10.0;
    low[1]=-10.0;high[1]=10.0;
    fa fax=new fa();
   
    double a[]=simulatedannealing(fax,low,high,20);
    String s="simulated annealing (tavlama simulasyonu) metodu sonucu =\n"+Matrix.toStringT(a);
    String s2="simulated annealing :";
    JOptionPane.showMessageDialog(null,s,s2,JOptionPane.PLAIN_MESSAGE);     
    }
}