import java.io.*;
import java.text.*;
import java.util.Locale;


public class iteratedhillclimber
{
	// Maximizing a function
    //iterated hill climber
    // a version steepest ascent with statistical approach to variable (endikyamaç)
    genotype1 Vc;
    genotype1 Vn[];
    genotype1 best;
    int MAX;
    double t;
    boolean local;
    int POPSIZE;
    int NVARS;
    int N;//number of bit representation for each variable
    
    //f_xj f;  // function to be avaluated by genetic algorithm
    
    public iteratedhillclimber(int iPOPSIZE,int iNVARS,int iN)
    {
    POPSIZE=iPOPSIZE;//Vn size number of neigbour variable f.e. 30
    NVARS=iNVARS; // number of variables equation to solve
    MAX=20;
    N=iN;            // number of bits represent each variable for example 32  
    Vn=new genotype1[POPSIZE+1];
    t=0;
    local=false;   
	}
		
	public void setVc(double low[],double up[],f_xj fi)
	{
	//select originalgene andomly	
	Vc=new genotype1(NVARS,low,up,N,fi);
	}
	public void setBest(genotype1 gi,f_xj fi)
	{
	//select originalgene andomly	
	best=new genotype1(gi,fi);
	}
    public void setVc(genotype1 gi,f_xj fi)
	{
	//select original gene from other gene
	Vc=new genotype1(gi,fi);
	}		
	public void setVn(f_xj fi)
	{//select neighbouring genes similar to the original one
	for(int i=0;i<POPSIZE+1;i++)
	  { Vn[i]=new genotype1(Vc,fi);}	
	   mutate(fi);  
	}
	
		
	public void evaluate(f_xj fi)
	{
	  int mem;
	  int j;
	  double x[]=new double[NVARS];
	  for(mem=0;mem<POPSIZE;mem++)
	  {
	  //System.out.println(Vn[mem].toString());	  
	  Vn[mem].setFitness(fi);
	  if(Vn[mem].getFitness() > Vn[POPSIZE].getFitness())
	     {
		 Vn[POPSIZE]=Vn[mem];    
	     for(j=0;j<NVARS;j++)
	        {
	        Vn[POPSIZE].G[j].copyGene(Vn[mem].G[j]);
		    }//end of for(j=0..
		 }//end of if
	  }//end of for(mem=0;..
	}
		
	public void toString(genotype Pi[])
	{
	int mem;
	int PN=Pi.length;	
	for(mem=0;mem<PN;mem++)
	{
	//list them	
	System.out.println("Vn["+mem+"]="+Pi[mem].toString());
	} 	
	}
	
		   
   public void mutate(f_xj fi)
   {
   int i;
   double lbound,hbound;
   int nmutations;
   int member;
   int var;
   nmutations=(int)((double)(POPSIZE*NVARS*N));
   for(i=0;i<nmutations;i++)
      {
      member=(int)(Math.random()*POPSIZE);
      var=(int)(Math.random()*NVARS);
      //replace the old value with a new mutated one
      Vn[member].G[var].mutate();
	  //after mutation recalculate the function value
      Vn[member].setFitness(fi); 
      }   	     	        
   }
   
   
   public double[] getBest(genotype1 b)
   {
   double aa[]=new double[NVARS+1];  
   for(int i=0;i < NVARS;i++)
     {
     aa[i]=b.getGene(i);
	 }
	 aa[NVARS]=b.getFitness();
   return aa;	      
   }
   
   public double[] calculate(double low[],double up[],f_xj fi,boolean report)
   {
     setVc(low,up,fi);// new set of random selection in each time	
     setBest(Vc,fi);
	 do
     {
	 local=true;       
     do
     {
     setVn(fi);
     evaluate(fi);
     if(Vn[POPSIZE].getFitness() > Vc.getFitness()) 
     {
	     setVc(Vn[POPSIZE], fi);
	     if(Vn[POPSIZE].getFitness() > best.getFitness()) setBest(Vn[POPSIZE],fi);
     }
     else local=false;
     } while(local);
     t++;
     setVc(low,up,fi); //new random value  
     if(report)
        System.out.println(Matrix.toString(getBest(best)));
     } while(t<MAX);	 
   return getBest(best);
   }      
}