/// OPTIMİZASYON
//  2 derece polinom interpolasyon kullanarak optimizasyon 
import java.util.*;
import java.awt.*;
import java.applet.Applet;
import java.awt.event.*;
import javax.swing.*;

class f_OPEKK extends f_x
{
  double E[][];
  public f_OPEKK(String s1,int m)
  {	  
  double x[];
  double y[];
  double a[][]=Text.readDoubleT(s1);
  x=a[0];
  y=a[1];
  E=OPEKK(x,y,m);
  }
  
  public double func (double x)
  { // polinom değerleri hesaplama fonksiyonu
    double yy=0;
    int k;
    int m=E[0].length-1;
    int mp2=m+2;
    double q[];
    q=new double[mp2];
    //vector<double> q(m+2,0.0);
    for(k=m-1;k>=0;k--)
    {
      q[k]=E[0][k]+(x-E[1][k+1])*q[k+1]-E[2][k+1]*q[k+2];
      yy=q[k];
    }
    return yy;
    }

public static double[][] OPEKK(double xi[],double fi[],int m)
//ortogonal polinom en küçük kareler metodu
//Referans : A First Course in Numerical Analysis
// Anthony Ralston,Philip Rabinowitz, Mc Graw Hill ISBN 0-07-051158-6 
//m polinom derecesi xi fi girdi verisi
{
int i,j,k;
int n=xi.length;
int mp2=n+2;
int mp1=n+1;
double p[][]=new double[mp2][n];
double gamma[]=new double[mp1];
double beta[]=new double[mp1];
double omega[]=new double[mp1];
double alpha[]=new double[mp1];
double b[]=new double[mp1];
double wi[]=new double[n];
double a[][]=new double[3][mp1];
for(i=0;i<n;i++)
  {
   p[1][i]=1.0;
   p[0][i]=0.0;
   wi[i]=1.0;
  }
gamma[0]=0;
for(i=0;i<n;i++)
  {
  gamma[0]+=wi[i];
  }
beta[0]=0.0;
for(j=0;j<m+1;j++)
  {
  omega[j]=0;
  for(i=0;i<n;i++)
    {omega[j]+=wi[i]*fi[i]*p[j+1][i];}
  b[j]=omega[j]/gamma[j];
if( j != m)
    {
    alpha[j+1]=0;
    for(i=0;i<n;i++)
      { alpha[j+1]+=wi[i]*xi[i]*p[j+1][i]*p[j+1][i]/gamma[j];}
    for(i=0;i<n;i++)
      {p[j+2][i]=(xi[i]-alpha[j+1])*p[j+1][i]-beta[j]*p[j][i];}
      gamma[j+1]=0;
    for(i=0;i<n;i++)
      {gamma[j+1]+=wi[i]*p[j+2][i]*p[j+2][i];}
    beta[j+1]=gamma[j+1]/gamma[j];
    }
}//end of j
for(j=0;j<m+1;j++)
  {
  a[0][j]=b[j];
  a[1][j]=alpha[j];
  a[2][j]=beta[j];
  }
return a;
}

}

public class FOPO1OPEKK
{
public static double golden(f_x f,double a,double b,double epsilon)
{return golden(f,a,b,epsilon,1.0e-10,0);}
public static double golden(f_x f,double a,double b)
{return golden(f,a,b,1.0e-10,1.0e-10,0);}
public static double golden(f_x f,double a,double b,double epsilon,double delta,int print)
{
//  f fonksiyonunun minimumunu bulur
// not  maximum f(x) = minimum (-f(x))
    double r1 = (Math.sqrt(5.0)-1.0)/2.0; // golden ratio
    double r2 = r1*r1;
    double h = b - a;
    double ya = f.func(a);
    double yb = f.func(b);
    double c = a + r2*h;
    double d = a + r1*h;
    double yc = f.func(c);
    double yd = f.func(d);
    int k = 1;
    double dp,dy,p,yp;
    while ((Math.abs(yb-ya)>epsilon) || (h>delta))
    {
      k++;
      if (yc<yd)
        {
        b = d;
        yb = yd;
        d = c;
        yd = yc;
        h = b - a;
        c = a + r2 * h;
        yc = f.func(c);
        }
      else
       {
         a = c;
         ya = yc;
         c = d;
         yc = yd;
         h = b - a;
         d = a + r1 * h;
         yd = f.func(d);
       }//end of if
    }//end of while
    dp = Math.abs(b-a);
    dy = Math.abs(yb-ya);
    p = a;
    yp = ya;
    if (yb<ya)
    {
      p = b;
      yp = yb;
    }
    if(print==1)
    {System.out.println("x min = "+p+"ymin = "+yp+"error of x ="+dp+"error of y"+dy); }
    return p;
}

     public static void main (String args[])  
     { 
	 f_OPEKK f=new f_OPEKK("in.txt",3);    
     double a,b;
     a=Double.parseDouble(JOptionPane.showInputDialog(" Fonksiyonun alt sınırını giriniz a : "));
     b=Double.parseDouble(JOptionPane.showInputDialog(" Fonksiyonun üst sınırını giriniz b : "));
     double r;
     r= golden(f,a,b,1.0e-10,1.0e-5,0);
     JOptionPane.showMessageDialog(null," optimizasyon değeri  : "+r+"\nFonksiyon değeri : "+f.func(r),
     "Fibonacchi optimizasyon : ",JOptionPane.PLAIN_MESSAGE);
     System.exit(0);
     } 
}
