import java.io.*;
import java.awt.Graphics;
import java.applet.Applet;

abstract class f_x
{
  //single function single independent variable
  // example f=x*x
  abstract double func(double x);
}

abstract class f_xi
{
  // multifunction multi independent variable
  // a single value is returned indiced to equation_ref
  // example f[0]=x[0]+sin(x[1])
  //         f[1]=x[0]*x[0]-x[1]
  // func(x,1) returns the value of f[1]
  // func(x,0) returns the value of f[0]
  abstract public double func(double x[],int equation_ref);
} //end of abstract class f_xi

class f6 extends f_xi
{
// user define function to be optimize
  public double func(double[] x, int i)
  {
  // minimum of f=x0^2+3*x0^2*x1-2*x0*x1*x2+5*x2^2
  double b;
  b=x[0]*x[0]+3*x[0]*x[0]*x[1]*x[1]-2*x[0]*x[1]*x[2]+5*x[2]*x[2];
  return b;
  }
} //end of class f6 user defined function definition to be minimized

class f7 extends f_x
{
  //steepest descent minimization (optimization) method
  public f6 b1;
  public double[] m;
  public double[] x;

  f7(double[] xi)
  {
  b1=new f6();
  x=xi;
  m=mi();
  }

  public void change_m(double[] xi)
  {x=xi;m=mi();}

  public double[] xi(double s)
  {
  double[] xx=new double[x.length];
  for(int i=0;i<x.length;i++)
     xx[i]=x[i]+m[i]*s;
  return xx;
  }

  public double[] mi()
  {
  double[] dy=new double[x.length];
  dy=derivative(b1,0,x);
  double mj[]=new double[x.length];
  double msum=0;
  for(int i=0;i<x.length;i++)
  {  msum+=dy[i]*dy[i]; }
  msum=Math.pow(msum,0.5);
  for(int i=0;i<x.length;i++)
  { mj[i]=-dy[i]/msum;}
  return mj;
  }

  public double func(double s)
  {
  for(int i=0;i<x.length;i++)
  {
  x[i]+=m[i]*s;
  }
  return b1.func(x,0);
  }

  public double[] derivative(f_xi f_deriv,int equation_ref,
  double x[])
  {
  // This method calculates derivative of a function selected from a set of
  // functions. Accuracy of method can be adjusted by changing
  // variables h0 and n
  // function input should be in the form given in abstract class
  // f_xi
  // df(equation_ref)/dx(x_ref)
  double h0=0.0256;
  int i,m;
  int n=7;
  double x1[];
  x1=new double[x.length];
  double x2[];
  x2=new double[x.length];
  for(i=0;i<x.length;i++)
  {
  x1[i]=x[i];
  x2[i]=x[i];
  }
  //derivative of a simple function
  double T[][];
  T=new double[n][n];
  double h[];
  h=new double[n];
  double xx[]=new double[x.length];
  int x_ref;
  for(x_ref=0;x_ref<x.length;x_ref++)
  {
  //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++)
  {
  x1[x_ref]+=h[i];
  x2[x_ref]-=h[i];
  T[i][0]=( f_deriv.func(x1,equation_ref) -
          f_deriv.func(x2,equation_ref))/(2.0*h[i]);
  x1[x_ref]=x[x_ref];
  x2[x_ref]=x[x_ref];
  }
  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]);
  }
  }
  xx[x_ref]=T[0][n-1];
  }
  return xx;
  }

}  // end of class f7

public class PROBLEM11_10 extends Applet
{

// Solve the given set of equations
    public void paint(Graphics g)
    {
    double[] x=new double[3];
    x[0]=-2;
    x[1]=3;
    x[2]=4;
    f7 b2=new f7(x);
    double s=0;
    for(int i=0;i<20;i++)
       {
       double yold=b2.b1.func(b2.xi(0.0),0);
       double ynew;
       for(s=0.0001;s<=10;s+=0.0001)
          {
          ynew=b2.b1.func(b2.xi(s),0);
          if(ynew<yold) yold=ynew;
          else break;
          }
       g.drawString("s = "+s+" yold="+yold+" x[0] = "+b2.x[0]+" x[1] = "+b2.x[1]+" x[2] = "+b2.x[2],25,55+i*15);
       if(Math.abs(yold)<1e-6) break;
       b2.change_m(b2.xi(s));
    }
    }
}


