import java.io.*;
import javax.swing.*;
class ff extends f_x
{
public double func(double x)
{return 2*x*x-3*x+4;}
}

// Trigonometric  rational approximation
class Trigonometric1
{ 
public double a[];
public double b[];
public double x0,xn;

public Trigonometric1(f_x f,double x0i,double xni,int n)
{
a=new double[n+1];
b=new double[n+1];
x0=x0i;
xn=xni;
for(int k=0;k<n;k++)
{a[k]=adaptive_Lobatto_integral(f,-Math.PI,Math.PI,k,0);}
b[0]=0.0;
for(int k=1;k<n;k++)
{b[k]=adaptive_Lobatto_integral(f,-Math.PI,Math.PI,k,1);}
b[n]=0;
}

public double z_x(double x)
{double zz=2.0*Math.PI*(x-x0)/(xn-x0)-Math.PI;
 return zz;
}

public double x_z(double z)
{double xx=(z+Math.PI)/(2.0*Math.PI)*(xn-x0)+x0;
 return xx;
}
public  double fak(f_x f,int k,double z)
    {   double a=0;
        double mult=2.0/(xn-x0);
	    a=mult*f.func(x_z(z))*Math.cos(k*z);
	    return a;
	}
	
public  double fbk(f_x f,int k,double z)
    {   double a=0;
        double mult=2.0/(xn-x0);
	     a=mult*f.func(x_z(z))*Math.sin(k*z);
	    return a;
	}
	
public double adaptive_Lobatto_integral(f_x f,double a,double b,int k,int eqn_type)
{   
	int i;
	double m=(a+b)/2.0; double h=(b-a)/2.0;
    double alpha=Math.sqrt(2.0/3.0); 
    double beta=1.0/Math.sqrt(5.0);
    double x1,x2,x3;
    x1=0.94288241569547971905635175843185720232; 
    x2=0.64185334234578130578123554132903188354;
    x3=0.23638319966214988028222377349205292599;
    double A,B,C,D,E,F,G;
    A=0.015827191973480183087169986733305510591;
    B=0.094273840218850045531282505077108171960;
    C=0.15507198733658539625363597980210298680;
    D=0.18882157396018245442000533937297167125;
    E=0.19977340522685852679206802206648840246;
    F=0.22492646533333952701601768799639508076;
    G=0.24261107190140773379964095790325635233;
	double x[]={a,(m-x1*h),(m-alpha*h),(m-x2*h),(m-beta*h),(m-x3*h),m,(m+x3*h),(m+beta*h),(m+x2*h),(m+alpha*h),(m+x1*h),b};
	int n=x.length;
	double y[]=new double[n];
	for(i=0;i<n;i++) 
	{
	if(eqn_type==0)
	{y[i]=fak(f,k,x[i]);}
	else
	{y[i]=fbk(f,k,x[i]);}
    }
	double fa=y[0]; 
	double fb=y[12];
    double i2=(h/6.0)*(y[0]+y[12]+5.0*(y[4]+y[8]));
    double i1=(h/1470.0)*(77.0*(y[0]+y[12])+432.0*(y[2]+y[10])+
     625.0*(y[4]+y[8])+672.0*y[6]);
    double is=h*(A*(y[0]+y[12])+B*(y[1]+y[11])+C*(y[2]+y[10])+D*(y[3]+y[9])+E*(y[4]+y[8])+F*(y[5]+y[7])+G*y[6]);    
    int s=(int)(is/Math.abs(is)); 
    if(s==0) s=1;
    double erri1=Math.abs(i1-is);
    double erri2=Math.abs(i2-is);
    double R; 
    R=erri1/erri2;
    //if(R>0 && R<1) tol=tol/R;
    //is=s*Math.abs(is)*tol/eps; 
    if(is==0) is=b-a;
  double Q=0;  
  Q=Lobatto(f,a,b,fa,fb,is,k,eqn_type);
  return Q;	
}
	
public  double Lobatto(f_x f,double a,double b,double fa,double fb,double is,int k,int eqn_type)
{
  double h=(b-a)/2; 
  double m=(a+b)/2;
  double alpha=Math.sqrt(2.0/3.0); 
  double beta=1.0/Math.sqrt(5.0);
  double mll=m-alpha*h; 
  double ml=m-beta*h; 
  double mr=m+beta*h; 
  double mrr=m+alpha*h;
  double x[]={mll,ml,m,mr,mrr};
  int n=x.length;
  double y[]=new double[n];
  for(int i=0;i<n;i++) 
  	{
    if(eqn_type==0)
	{y[i]=fak(f,k,x[i]);}
	else
	{y[i]=fbk(f,k,x[i]);}
    }
  double fmll=y[0]; 
  double fml=y[1]; 
  double fm=y[2]; 
  double fmr=y[3]; 
  double fmrr=y[4];
  double Q;
  double i2=(h/6)*(fa+fb+5*(fml+fmr));
  double i1=(h/1470)*(77*(fa+fb)+432*(fmll+fmrr)+625*(fml+fmr)+672*fm);
  boolean c1,c2,c3;
  double w1=i1-i2;;
  double w2=is;
  double w3=w2+w1;  
  c1=(w3==w2);
  c2=(mll<=a);
  c3=(b<=mrr);
  if( c1|| c2 ||c3 )
  {
   if (((m <= a) || (b<=m)))
   {
       System.out.println("istenilen toleransa ulaşılamadı");
   }
   Q=i1;
  }  
  else
  {
    Q=Lobatto(f,a,mll,fa,fmll,is,k,eqn_type) + Lobatto(f,mll,ml,fmll,fml,is,k,eqn_type)+
      Lobatto(f,ml,m,fml,fm,is,k,eqn_type)   + Lobatto(f,m,mr,fm,fmr,is,k,eqn_type)+
      Lobatto(f,mr,mrr,fmr,fmrr,is,k,eqn_type)+Lobatto(f,mrr,b,fmrr,fb,is,k,eqn_type);
  }
  return Q;
}

//=============   




  
public  double func(double z)
{
int n=a.length-1;
double cc=a[0]/2.0+a[n]*Math.cos(n*z)+b[n]*Math.sin(n*z);
for(int k=1;k<n;k++)
{cc+=a[k]*Math.cos(k*z)+b[k]*Math.sin(k*z);}
return cc;
}

public  double funcx(double x)
{
double z=z_x(x);
int n=a.length-1;
double cc=a[0]/2.0+a[n]*Math.cos(n*z)+b[n]*Math.sin(n*z);
for(int k=1;k<n;k++)
{cc+=a[k]*Math.cos(k*z)+b[k]*Math.sin(k*z);}
return cc;
}

public void plot_func(f_x f,double x0i,double xni )
{	double xx[]=new double[101];
    double yy[]=new double[101];
    double x1[]=new double[101];
    double y1[]=new double[101];
    double z1=0;
	for(int i=0;i<=100;i++)
	{z1=x0i+i*(xni-x0i)/100.0;xx[i]=x_z(z1);yy[i]=func(z1);
	 x1[i]=xx[i];y1[i]=f.func(x1[i]);
	}
	
	Plot pp=new Plot(xx,yy);
	pp.addData(x1,y1);
    pp.setPlabel("Trigonometric rational approximation function n="+(a.length-1));
	pp.plot();
}

	public void plot_error(f_x f,double x0i,double xni)
    { double xx[]=new double[101];
      double yy[]=new double[101];
      double z1=0;
	  for(int i=0;i<=100;i++)
	  {z1=x0i+i*(xni-x0i)/100.0;
	   xx[i]=x_z(z1);yy[i]=func(z1)-f.func(xx[i]);
	  }
	Plot pp=new Plot(xx,yy);
    pp.setPlabel("Trigonometric rational approximation error n = "+(a.length-1));
    pp.setYlabel("error");
	pp.plot();
}

public String toString()
{
	String s="a : \n"+Matrix.toStringT(a)+"\n";
	      s+="b : \n"+Matrix.toStringT(b)+"\n";
	return s;
}

public String toString(f_x f,double a,double b,int n)
{
	
return Matrix.toStringT(result(f,a,b,n));
}

public double[][] result(f_x f,double a,double b,int n)
{   double xx[][]=new double[4][n+1];
    double z1=0;
    for(int i=0;i<=n;i++)
	{ z1=a+i*(b-a)/n;
      xx[0][i]=x_z(z1);
	  xx[1][i]=func(z1); 
	  xx[2][i]=f.func(x_z(z1));
	  xx[3][i]=xx[2][i]-xx[1][i];
	}
	return xx;
}


public static void print(String s,String s1)
{JOptionPane.showMessageDialog(null,s,s1,JOptionPane.PLAIN_MESSAGE);}
public static void main(String arg[])
{
	ff f=new ff();
	int n=Integer.parseInt(JOptionPane.showInputDialog("number of terms in the Trigonometric function approximation:"));
	double x0=-1.0;
	double xn=1.0;
	Trigonometric1 Pa=new Trigonometric1(f,x0,xn,n);
	print(Pa.toString(),"Trigonometric polynomials coefficients n="+n);
	String s1[]={"x","Trigonometric f(x)","f(x)","error"};
	Text.print(Text.T(Pa.result(f,-Math.PI,Math.PI,20)),s1,"Trigonometric polynomials n = "+n);
	Pa.plot_func(f,-Math.PI,Math.PI);
	Pa.plot_error(f,-Math.PI,Math.PI);
}

}
