import java.io.*;

public class  teaching_learning_based_optimization
{
double[] Lower;
double[] Upper;
int maxiter;
double[] XTEACHER;
double[] yXTEACHER;
double[][] X;
double[][] XNEW;
double[] MEAN;
double[] yX;
double ybest;
int N;
int D;
double[] BEST;
double Globalminimum;
double[] Globalminimizer;
int k1,k2;
f_xj ff;


public  teaching_learning_based_optimization(f_xj iff,int iN,double iLower[],double iUpper[],int imaxiter)
{
ff=iff;
maxiter=imaxiter;
Lower=iLower;
Upper=iUpper;
D=Lower.length;
N=iN;
Globalminimum=1000000000.0;
Globalminimizer=new double[D];
MEAN=new double[D];
XNEW=new double[N][D];
yX=new double[N];
yXTEACHER=new double[N];
X=new double[N][D];
XTEACHER=new double[D];
BEST=new double[maxiter];
}


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

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

double[][] solution()
{
initialize();
int iter = 0;
int mindex;
    while(iter < maxiter)
    {
	  
	    // Teaching learning based optimization
			for(int i=0;i<N;i++)
			{yXTEACHER[i]=ff.func(X[i]);}
			
			double[] d3=getminval_index(yXTEACHER);
			int mindex2=(int)d3[1];
			
			for(int i=0;i<D;i++)
			{XTEACHER[i]=X[mindex2][i];}
			double TF;
			double sum1;
			for(int j=0;j<D;j++)
			{sum1=0.0;
			   	for(int i=0;i<N;i++)
			   	{sum1+=X[i][j];}
				MEAN[j]=sum1/(double)N;}			
			for(int i=0;i<N;i++)
			{for(int j=0;j<D;j++)
			   {TF=Math.round(1.0+Math.random());
				   XNEW[i][j]=X[i][j]+Math.random()*(XTEACHER[j]-(TF*MEAN[j]));}}			   
			   for(int i=0;i<N;i++)
			   {if(ff.func(XNEW[i])<ff.func(X[i]))
			       {for(int j=0;j<D;j++)
			          {X[i][j]=XNEW[i][j];}}}  
			          
			 // Learner phase
			 
			 for(int i=0;i<N;i++)
			 {
				 k1=(int)Math.floor((double)N*Math.random());
	       	    
				 
	       	     while(i==k1)
	       		 {k1=(int)Math.floor((double)N*Math.random());}
	   
	       		 if(ff.func(X[k1])<ff.func(X[i]))
	       		 {
		       	    for(int j=0;j<D;j++)
		       	    {XNEW[i][j]=X[i][j]+Math.random()*(X[k1][j]-X[i][j]);}
		       		  	 
		       	 }
	       		 else
	       		 {
		       	    for(int j=0;j<D;j++)
		       	    {XNEW[i][j]=X[i][j]+Math.random()*(X[i][j]-X[k1][j]);}	 		       		 
		       	 }				 
		      }
		      
		      for(int i=0;i<N;i++)
		      {
			     if(ff.func(XNEW[i])<ff.func(X[i]))
			     {
				     for(int j=0;j<D;j++)
				     {X[i][j]=XNEW[i][j];}    
				     
				 }    
			  }          
	    
			  for(int i=0;i<N;i++)
			  {yX[i]=ff.func(X[i]);}
			  
			  double[] d4=getminval_index(yX);
			  ybest=d4[0];
			  int mindex3=(int)d4[1];
	          
			  if (ybest<Globalminimum)
	          {
		          Globalminimum=ybest;
	              for(int j=0;j<D;j++)
	              {Globalminimizer[j]=X[mindex3][j];}
	          }
	    
	          BEST[iter]=Globalminimum;
	          iter++;
	    }
	    
	        double[] plott=new double[maxiter];
		    for(int i=0;i<maxiter;i++)
		    {plott[i]=i;}
		    //Plot pp1=new Plot(plott,BESTvar1);
		    //pp1.plot();
            //Plot pp2=new Plot(plott,BESTvar2);
		    //pp2.plot();
		    //Plot pp3=new Plot(plott,BESTvar3);
		   // pp3.plot();
		    Plot pp4=new Plot(plott,BEST);
		   // pp4.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  toStringneww()
{
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 toTxtfile()
{           String named="tlbo_37_drop100.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();}			   
		}
}