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

abstract class f_xy
{
  //single function single independent variable
  // example f=x*x
  abstract double func(double x,double y);
}
abstract class f_xi
{
  // çok fonksiyonlu ve çok denklemli fonksiyon
  // denklemlerin sadece bir tanesi denklem_ref
  // tarafından seçilir.
  // örnek   f[0]=x[0]+sin(x[1])
  //         f[1]=x[0]*x[0]-x[1]
  // func(x,1)  f[1] değerini verir
  // func(x,0)  f[0] değerini verir

  abstract double func(double x[],int denklem_ref);
}
public class Runge_Kutta
{
double a[][];
double b[][];
double c[];

public Runge_Kutta(double ai[][],double bi[][],double ci[])
{a=ai;b=bi;c=ci;}

public Runge_Kutta(Buthcher bu)
{a=bu.a;b=bu.b;c=bu.c;}
public Runge_Kutta(String isim)
{Buthcher bu=new Buthcher(isim); 
 a=bu.a;b=bu.b;c=bu.c;
}
public double[][] hesapla(f_xy f,double x0,double xn,double y0,double h)
{return hesapla(f,x0,xn,y0,h,0);}

public double[][] hesapla(f_xy f,double x0,double xn,double y0,double h,int bk)
{ 
  int n=(int)((xn-x0)/h);
  double x[]=new double[n+1];
  double y[]=new double[n+1];
  int s=c.length;
  double xi;
  double yi;
  double ki[]=new double[s];
  x[0]=x0;y[0]=y0;
  for(int ni=0;ni<n;ni++)
  {for(int i=0;i<s;i++)
   { xi=x[ni]+c[i]*h;
     yi=y[ni];
    for(int j=0;j<i;j++)
    {yi+=h*a[i][j]*ki[j];//System.out.println("xi(0)="+xi+"xi(j)="+yi+"i="+i+"j="+j+"ki="+ki[j]);
    }
    ki[i]=f.func(xi,yi);
    //System.out.println("ki="+ki[i]); 
   }
   y[ni+1]=y[ni];
   for(int i=0;i<s;i++)
    {y[ni+1]+=h*b[bk][i]*ki[i];}
   x[ni+1]=x[ni]+h;
  }
  double XY[][]=new double[2][n+1];
  XY[0]=x;
  XY[1]=y;
  return XY;
}
public static double[] tasi(double x1,double y1[])
{
int n=y1.length;
double z[]=new double[n+1];
z[0]=x1;
for(int i=1;i<=n;i++)
{z[i]=y1[i-1];}
return z;	
}
//çok boyutlu RK girişler N(toplam veri sayısı) veya h(step boyu) üzeriinden verilebilmektedir.
public double[][] hesapla(f_xi f,double x0,double xn,double y0[],double h)
{return hesapla(f,x0,xn,y0,h,0);}
public double[][] hesapla(f_xi f,double x0,double xn,double y0[],int ni)
{double h=(xn-x0)/ni;
return hesapla(f,x0,xn,y0,h,0);
}
public double[][] hesapla(f_xi f,double x0,double xn,double y0[],int ni,int bk)
{double h=(xn-x0)/ni;
return hesapla(f,x0,xn,y0,h,bk);
}
public double[][] hesapla(f_xi f,double x0,double xn,double y0[],double h,int bk)
{ 
  int n=(int)((xn-x0)/h);
  int m=y0.length;
  double x[]=new double[n+1];
  double y[][]=new double[n+1][m];
  int s=c.length;
  double xi;
  double yi;
  double z[]=new double[m+1];
  double ki[]=new double[s];

  x[0]=x0;
  for(int ni=0;ni<=n;ni++)
  {x[ni]=x0+ni*h;}
  y[0]=y0;
  for(int ni=0;ni<n;ni++)
  { for(int k=0;k<m;k++)
	{  
      for(int i=0;i<s;i++)
      { xi=x[ni]+c[i]*h;
        z=tasi(xi,y[ni]);
        for(int j=0;j<i;j++)
           {z[k+1]+=h*a[i][j]*ki[j];//System.out.println("xi(0)="+z[0]+"xi(j)="+z[k+1]+"i="+i+"j="+j+"ki="+ki[j]); 
           }
        ki[i]=f.func(z,k);
        //System.out.println("ki="+ki[i]); 
      }
   y[ni+1][k]=y[ni][k];
   for(int i=0;i<s;i++)
    {y[ni+1][k]+=h*b[bk][i]*ki[i];}
  }
  }
  double XY[][]=new double[m+1][n+1];
  XY[0]=x;
  for(int k=0;k<m;k++)
   { for(int ni=0;ni<=n;ni++)
     {XY[k+1][ni]=y[ni][k];}
   }
  return XY;
}

public static String toString(double left, int w, int d)
// converts a double to a string with given width and decimals.
{
	NumberFormat df=NumberFormat.getInstance(Locale.US);
	df.setMaximumFractionDigits(d);
    df.setMinimumFractionDigits(d);
    df.setGroupingUsed(false);
    String s = df.format(left);
    while (s.length() < w)
      s = " " + s;
    if (s.length() > w)
    {
        s = "";
        for (int i=0; i<w; i++)
          s = s + "-";
    }
    return s;
}
public String toString()
 {int m=b[0].length;
  int n=c.length;
  int k=b.length;
  String s="Buthcher tablosu n = "+n+"\n";
  for(int i=0;i<n;i++)
  {s+=toString(c[i],15,8)+" | ";
  for(int j=0;j<i;j++)
  {s+=toString(a[i][j],15,8)+" ";}
  s+="\n";
  }
  for(int j=0;j<m;j++)
  {s+="------------------";}
  s+="\n                  ";
  for(int i=0;i<k;i++)
  {
  for(int j=0;j<m;j++)
  {s+=toString(b[i][j],15,8)+" ";}
   s+="\n                  ";
  }
   return s;	 
 }
}
