/// OPTIMİZASYON
//  Newton-ikiyebölme kök bulma yöntemi (ve türev ) kullanarak optimizasyon 
import java.util.*;
import java.awt.*;
import java.applet.Applet;
import java.awt.event.*;
import javax.swing.*;

class fc extends f_x
{
   public double func(double D)
   {   double V=0.5e-3;
	   return Math.PI*D*D/2.0+4.0*V/D;}
}

class fb extends f_x
{
   public double func(double D)
   { double V=0.5e-3;
     return Math.PI*D-4.0*V/(D*D);}
}

public class FOPO3D
{

public static double derivative(f_x df,double x)
{
// türev alt programı	
// df fonksiyonunun türevini hesaplar
double h0=0.256;
int i,m;
int n=7;
//derivative of a simple function
double T[][];
T=new double[n][n];
double h[];
h=new double[n];
//vector<double> h(n,0);
for(i=0;i<n;i++)
{
  h[i]=0;
  for(int j=0;j<n;j++)
    T[i][j]=0;
}
h[0]=h0;
double r=0.5;
for( i=1;i<n;i++)
{
h[i]=h0*Math.pow(r,i);
}

for(i=0;i<n;i++)
{
T[i][0]=( df.func(x + h[i]) - df.func( x - h[i]))/(2.0*h[i]);
}
for(m=1;m<n;m++)
{
  for(i=0;i<n-m;i++)
  {
  T[i][m]=(h[i]*h[i]*T[i+1][m-1] - h[i+m]*h[i+m]*T[i][m-1])/
          (h[i]*h[i]- h[i+m]*h[i+m]);
  }
}
double xx=T[0][n-1];
return xx;
}

public static double dfx(f_x f,double x,double h)
{ //Türev hesabı
  double hh=1.0/h; 
  return (-f.func(x+2.0*h)+8.0*f.func(x+h)-8.0*f.func(x-h)+f.func(x-2.0*h))/12.0*hh;
}

public static double brent(f_x f,double x1,double x2)
{
    //lineer olmıyan denklemin kökü : brent metodu
	//referans : Numerical Recipes in C, second edition, William H. Press, 
    //Saul A. Teukolsky, William T. Vetterling, Brian P. Flannery
    //cambridge university press	
	double ITMAX=100;
    double EPS=3.0e-8;
	int iter;
	double a=x1,b=x2,c,d,e,min1,min2;
	double tol=1.0e-5;
	c=0;
	d=0;
	e=0;
	double fa=f.func(a),fb=f.func(b),fc,p,q,r,s,tol1,xm;
	if (fb*fa > 0.0) JOptionPane.showMessageDialog(null,"Kök sınırları doğru olarak seçilmemiş \n sonuç hatalı olabilir"
	,"KÖK SINIRLARI SEÇİM UYARISI",JOptionPane.WARNING_MESSAGE);
	fc=fb;
	for (iter=1;iter<=ITMAX;iter++) {
		if (fb*fc > 0.0) {
			c=a;
			fc=fa;
			e=d=b-a;
		}
		if (Math.abs(fc) < Math.abs(fb)) {
			a=b;
			b=c;
			c=a;
			fa=fb;
			fb=fc;
			fc=fa;
		}
		tol1=2.0*EPS*Math.abs(b)+0.5*tol;
		xm=0.5*(c-b);
		if (Math.abs(xm) <= tol1 || fb == 0.0) return b;
		if (Math.abs(e) >= tol1 && Math.abs(fa) > Math.abs(fb)) {
			s=fb/fa;
			if (a == c) {
				p=2.0*xm*s;
				q=1.0-s;
			} else {
				q=fa/fc;
				r=fb/fc;
				p=s*(2.0*xm*q*(q-r)-(b-a)*(r-1.0));
				q=(q-1.0)*(r-1.0)*(s-1.0);
			}
			if (p > 0.0)  q = -q;
			p=Math.abs(p);
			min1=3.0*xm*q-Math.abs(tol1*q);
			min2=Math.abs(e*q);
			if (2.0*p < (min1 < min2 ? min1 : min2)) {
				e=d;
				d=p/q;
			} else {
				d=xm;
				e=d;
			}
		} else {
			d=xm;
			e=d;
		}
		a=b;
		fa=fb;
		if (Math.abs(d) > tol1)
			b += d;
		else
			b += (xm > 0.0 ? Math.abs(tol1) : -Math.abs(tol1));
		fb=f.func(b);
	}
	JOptionPane.showMessageDialog(null,"Uyarı maximum iterasyon sayısı aşıldı \n"+
   " çözüm geçerli olmıyabilir","MAKSİMUM ITERASYON SAYISI UYARISI",JOptionPane.WARNING_MESSAGE);
return b;
}

     public static void main (String args[])  
     { 
	 fc  f=new fc();
	 fb df=new fb();  
     double x0,x1;
     x0=Double.parseDouble(JOptionPane.showInputDialog(" alt sınırı giriniz  x0 : "));
     x1=Double.parseDouble(JOptionPane.showInputDialog(" üst sınırı giriniz  x1 : "));
     double r;
     r= brent(df,x0,x1);
     JOptionPane.showMessageDialog(null," optimizasyon değeri  : "+r+"\nFonksiyon değeri : "+f.func(r),
     "brent kök bulma yöntemiyle optimizasyon : ",JOptionPane.PLAIN_MESSAGE);
     System.exit(0);
     } 
}