import java.io.*;
import java.util.*;
import javax.swing.*;
import java.awt.event.*;

//yüzey eğri uydurma
//f(x,y)=a0+a1*x+a2*y+a3*x^2+a4*y^2+a5*xy+a6*x^3+a7*y^3+a8*x^2y
//      +a9*xy^2+a10*x^4+a11*y^4+a12*x^2y^2+a13x^3y+a14*xy^3
abstract class f_xir
{
  abstract double func(double x[],int equation_ref);
}

class fa extends f_xir
{	
	double func(double x[],int i)
	{//genel bir yüzey modeli	
    double xx=0.0;
    //density function 		
    if(i==0)       {xx=1.0;           }
    else if (i==1) {xx=x[0];          }
    else if (i==2) {xx=x[1];          }
    else if (i==3) {xx=x[1]*x[0];     }
    else if (i==4) {xx=x[1]*x[1];     }
    else if (i==5) {xx=x[0]*x[0];     }
    else if (i==6) {xx=x[0]*x[0]*x[1];     }
    
    return xx;
	}
}    

class SCO11G5
{
//  Genel en küçük kareler metodu en kucuk kareler metodu	
	public static double[][] Transpose(double [][] left)
    { //transpose matrix (if A=a(i,j) Transpose(A)=a(j,i)
    int i,j;
    int n=left.length;
    int m=left[0].length;
    double b[][];
    b=new double[m][n];
    for(i=0;i<n;i++)
      {for(j=0;j<m;j++)  {b[j][i]=left[i][j];} }
    return b;
    }  
    
  public static double[] pivotlugauss(double a[][],double b[])
  { //kısmi pivotlu gauss eleme yöntemi
  int n=b.length;	  
  double x[]=new double[n];
  double carpan=0;
  double toplam=0;
  double buyuk;
  double dummy=0;
  //gauss eleme
  int i,j,k,p,ii,jj;
  for(k=0;k<(n-1);k++)
  { //pivotlama
	p=k;
	buyuk=Math.abs(a[k][k]);
	for(ii=k+1;ii<n;ii++)
	{  dummy=Math.abs(a[ii][k]);
	   if(dummy > buyuk) {buyuk=dummy;p=ii;}
	}
	if(p!=k)
	{ for(jj=k;jj<n;jj++)
	  { dummy=a[p][jj];
	    a[p][jj]=a[k][jj];
	    a[k][jj]=dummy;
	  }
	  dummy=b[p];
	  b[p]=b[k];
	  b[k]=dummy;
	}
	//gauss elemeyi çözme  
    for(i=k+1;i<n;i++)
    {  carpan=a[i][k]/a[k][k];
       a[i][k]=0;
       for(j=k+1;j<n;j++)
       {   a[i][j]-=carpan*a[k][j]; }
           b[i]   =b[i]   -carpan*b[k];
	}
  }
  //geriye doğru yerine koyma
  x[n-1]=b[n-1]/a[n-1][n-1];
  for(i=n-2;i>=0;i--)
  {
    toplam=0;
    for(j=i+1;j<n;j++)
    {  toplam+=a[i][j]*x[j];}
    x[i]=(b[i]-toplam)/a[i][i];
  }
  return x;
}

public static double[] EKKgenel(double c[][],int n)
{
int n1=c.length;
  int n2=c[0].length-1;
  System.out.println("n1="+n1+"n2="+n2);
  double xi[][]=new double[n1][n2];
  double yi[]=new double[n1];
  for(int i=0;i<n1;i++){for(int j=0;j<n2;j++){xi[i][j]=c[i][j];};yi[i]=c[i][n2];}
  return EKKgenel(xi,yi,n);
}

public static double[] EKKgenel(double xi[][],double yi[],int n)
{ // n boyutlu yüzey eğri uydurma
  // yüzey EKK katsayılarını hesaplar
fa f=new fa();
int l=xi.length;
int i,j,k;
int np1=n+1;
double A[][];
A=new double[np1][np1];
double B[];
B=new double[np1];
double X[];
X=new double[np1];
for(i=0;i<n+1;i++)
  {  B[i]=0;
	 for(j=0;j<np1;j++)
     {
	 A[i][j]=0.0;    
     for(k=0;k<l;k++) A[i][j]+=f.func(xi[k],i)*f.func(xi[k],j);
     }
     for(k=0;k<l;k++) B[i]+= f.func(xi[k],i)*yi[k];
  }
//System.out.println("A = \n"+Matrix.toString(A));
//System.out.println("B = \n"+Matrix.toStringT(B));  
X=pivotlugauss(A,B);
//X=B/A;
double max=0;
for(i=0;i<n+1;i++)
 if(Math.abs(X[i]) > max) max = Math.abs(X[i]);
for(i=0;i<n+1;i++)
 if((Math.abs(X[i]/max) > 0) && (Math.abs(X[i]/max) < 1.0e-100)) X[i]=0;
Text.printT(X); 
return X;
}

public static double funcEKKgenel(double e[],double x[])
{
// tek bir nokta için çok boyutlu eğri değeri hesaplar
fa f=new fa();
int n=e.length;
double ff=0;
if(n!=0.0)
  { 
  for(int i=n-1;i>=0;i--)
   {ff+=e[i]*f.func(x,i);}
  } 
return ff;
}

public static double[] funcEKKgenel(double e[],double xi[][])
{
// tek bir nokta için çok boyutlu eğri değeri hesaplar
fa f=new fa();
int n=e.length;
double ff[]=new double[xi.length];
for(int k=0;k<xi.length;k++)
{
if(n!=0.0)
  { 
  for(int i=n-1;i>=0;i--)
   {ff[k]+=e[i]*f.func(xi[k],i);}
  }
} 
return ff;
}

public static double[][] cikti(double c[][],int polinomkatsayisi,int aradegersayisi)
{ int n1=c.length;
  int n2=c[0].length-1;
  System.out.println("n1="+n1+"n2="+n2);
  double xi[][]=new double[n1][n2];
  double yi[]=new double[n1];
  for(int i=0;i<n1;i++){for(int j=0;j<n2;j++){xi[i][j]=c[i][j];};yi[i]=c[i][n2];
  }
  return cikti(xi,yi,polinomkatsayisi,aradegersayisi);
}


public static double[][] cikti(double xi[][],double yi[],int polinomkatsayisi,int aradegersayisi)
{
	int n=xi.length;
	int nk=xi[0].length;
	int nn=(n-1)*(aradegersayisi+1)+1;
    double E[]=EKKgenel(xi,yi,polinomkatsayisi);
    double x[][]=new double[nn][nk];
    double c[][]=new double[nn][nk+1];	
    double yy[]=new double[nn];
    double dx[]=new double[nk];
    int k=0;
    int i,j,w;
    for(i=0;i<(n-1);i++)
       {   for(w=0;w<nk;w++){x[k][w]=xi[i][w];dx[w]=(xi[i+1][w]-xi[i][w])/((double)aradegersayisi+1.0);};k++;
           for(j=0;j<aradegersayisi;j++)
           { for(w=0;w<nk;w++){x[k][w]=x[k-1][w]+dx[w];};k++;}
       }
    for(w=0;w<nk;w++){x[k][w]=xi[i][w];}   
    yy=funcEKKgenel(E,x);
    for(i=0;i<x.length;i++)
      {for(w=0;w<nk;w++) c[i][w]=x[i][w];
       c[i][nk]=yy[i];
      }
    return c;
}

public static double funcEKKgenel(double e[],double x,double y)
{
// yüzey uydurma fonksiyonu
// tek bir nokta için iki boyutlu eğri değeri hesaplar
double xx[]=new double[2];
xx[0]=x;
xx[1]=y;
return funcEKKgenel(e,xx);
}

public static double hata(double c[][],double e[])
{int n1=c.length;
  int n2=c[0].length-1;
  System.out.println("n1="+n1+"n2="+n2);
  double xi[][]=new double[n1][n2];
  double yi[]=new double[n1];
  for(int i=0;i<n1;i++){for(int j=0;j<n2;j++){xi[i][j]=c[i][j];};yi[i]=c[i][n2];
  }
return hata(xi,yi,e);  
}

public static double hata(double x[][],double y[],double e[])
{
//calculates absolute square root error of a least square approach
double n=x.length;
 int k;
 double total=0;
 for(k=0;k<n;k++)
 {
 total+=(y[k]-funcEKKgenel(e,x[k]))*(y[k]-funcEKKgenel(e,x[k]));
 }
total=Math.sqrt(total);
return total;
}
 
  public static void main(String[] args) 
  {
  String s1=JOptionPane.showInputDialog("dosya adı : ");	  
  double c[][]=Text.readDouble(s1);
  //Text.print(c);
  double b[]=EKKgenel(c,4);
  double xi[][]=cikti(c,4,2);
  System.out.println("cikti \n"+Matrix.toString(xi)); 
  System.out.println("hata \n"+Matrix.toString(hata(c,b)));   
  }
}