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

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

public class harmony
{
int Maxiter;
double range[][];
double pa_range[];
int HS_size;
double HMacceptRate;
double PArate;
int ndim;
double[] x;
double[][] HM;
double[] HM_best;
f_xj ff;

      public harmony(f_xj ffi,int iMaxiter,int iHS_size,double iHMacceptRate,double iPArate,double[][] irange,double ipa_range[])
      {
	   Maxiter=iMaxiter;
	   HS_size=iHS_size;
	   HMacceptRate=iHMacceptRate;
	   PArate=iPArate;
	   range=irange;
	   pa_range=ipa_range;
	   ndim=pa_range.length;
	   x=new double[ndim];
	   HM=new double[HS_size][ndim];
	   HM_best=new double[HS_size];
	   ff=ffi;
	  }

	  
	  
	  void initialize()
	  {
	     for(int i=0;i<HS_size;i++)
	        {
	        for(int j=0;j<ndim;j++)
	        {
		    x[j]=range[j][0]+(range[j][1]-range[j][0])*Math.random();        
		    }
		    	       
		    for(int l=0;l<ndim;l++)
		    {
			HM[i][l]=x[l]; 
			}
		        
		    HM_best[i]=ff.func(x); 
		    }
	  }
	  
	  double[][] solution()
	  {     
		   double sol[]=new double[ndim];
            double pa=0.0;	
            double fbest=0.0;	  
		    initialize();
            
            for(int k=0;k<Maxiter;k++)
	        {
		         for(int t=0;t<ndim;t++)
		         {
			          if(Math.random()>=HMacceptRate)
			          {
				      x[t]=range[t][0]+(range[t][1]-range[t][0])*Math.random();    
				      }else{    
	                  x[t]=HM[(int)Math.floor(HS_size*Math.random())][t];
	                  
	                  if(Math.random()<=PArate)
	                  {
		              pa=(range[t][1]-range[t][0])/pa_range[t];    
		              x[t]=x[t]+pa*(Math.random()-0.5);    
		              }
	                  }
	             } 
		                 fbest=ff.func(x);
		                 int HSmaxNum=0;
		    			 int HSminNum=0;
		   				 double HSmax=HM_best[0];
		    			 double HSmin=HM_best[0];
		    
		   				 for (int i=1;i<HS_size;i++)
		       			 {
			   				if(HM_best[i]>HSmax)    
			   				{ 
		       				HSmaxNum = i;
               				HSmax = HM_best[i];
			   				}
			   				if(HM_best[i]<HSmin)
			   				{
			   				HSminNum=i;
               				HSmin=HM_best[i];   
			   				} 
						 }
		    
							if (fbest < HSmax)
            			    {  
	            			for(int j=0;j<ndim;j++)
	            			{     
	           				HM[HSmaxNum][j]=x[j];
           				    }
               				HM_best[HSmaxNum]=fbest;
            			    }
            				sol=x;
            				
               }
		   double depo[]=new double[x.length];
		   for(int i=0;i<x.length;i++)
		   {depo[i]=x[i];}
		   double dep[][]=new double[2][x.length];
           dep[0]=depo;
           dep[1][0]=fbest;    
           return dep;    
                  
      }
	  
       void output()
       {
	   double[][] solval=solution();
	   int mm=solval[0].length;    
	   double xx[]=new double[mm];    
	       for(int i=0;i<mm;i++)
	       {
		   xx[i]=solval[0][i];    
		   }
	       for(int i=0;i<mm;i++)
	       {
		   System.out.println("x["+i+"] = "+xx[i]);   
		   }
		   System.out.println("Optimum dešer = "+solval[1][0]);
	   }
}