/*
 * Created on 08.04.2005
 *
 * TODO To change the template for this generated file go to
 * Window - Preferences - Java - Code Style - Code Templates
 */

/**
 * @author GerberDom
 *
 * TODO To change the template for this generated type comment go to
 * Window - Preferences - Java - Code Style - Code Templates
 */

/*
 * 	Berechnet ein LGLS nach Jakobi oder Gauss. 
 * 	Numerik-Buch Seite 307. Kapitel 7.4
 *
 */

class Jakobi
{
	static int n = 4;							// Matrizengrösse
	private static final int  vorKomma = 2;		// Formatierung
	private static final int  nachKomma = 6;
	
	private static double[][]A = { {10, -1, 2,0} ,  {-1,11,-1,3}, { 2, -1, 10, -1}, {0,3,-1,8} };
	private static double[]  c = { 6, 25, -11, 15};
	private static double[] Xalt = new double[n];
	private static double[] Xneu = new double[n];
	private static double maxiDiff=1000;			// Delta zweier aufeinanderfolgenden Vektoren
	private static int anzIt = 25;					// Anz. Iterationen
	private static double err  = Math.pow(10, -7);	// Fehler
	

	public static void main(String [] args)
	{
		JakobiVerf();
		GaussSeidel();
		//-Einfache Berechnungsverfahren mittels Formel aus dem Buch Seite 307
		//JakobiEinfach();
		//GaussSeidelEinfach();
	}
	
	public static void JakobiEinfach()
	{
		getInfoJakobi();
		System.out.println("\ngegebene Matrix A: ");
		print(A);
		System.out.println("\nVektor b mit den Resultaten: ");
		print(c);
		System.out.println("");
		
		for(int i=0; i<n; i++)
		{
			double sum = 0.0;
			for(int j=0; j<n; j++)
			{
				if (j==i)
					continue;
				
				else
				{
					sum+= ((float)-A[i][j]*Xalt[j])/A[i][i];
				}	
			}
			Xneu[i] = sum + ((float)c[i])/A[i][i];
		}
		
		Xalt = Xneu;
		
		print(Xalt);
		System.out.println("");
	
		for(int l = 0; l<anzIt; l++)
		{
			for(int i =0; i<n; i++)
			{
				double sum = 0.0;
				for(int j=0; j<n; j++)
				{
					if(j==i)
						continue;
					else
					{
						sum+=(float)(-A[i][j]*Xalt[j]);
					}	
				}
				Xneu[i] = (sum + c[i])/A[i][i];	
			}
			System.out.print(l<10 ? " "+l+":" : ""+l+":");	
			printTranspose(Xneu);
			Xalt = Xneu;
		}
	}
	
	public static void GaussSeidelEinfach()
	{
		getInfoJakobi();
		System.out.println("\ngegebene Matrix A: ");
		print(A);
		System.out.println("\nVektor b mit den Resultaten: ");
		print(c);
		System.out.println("");
	
		Xalt = Xneu;
		print(Xalt);
		System.out.println("");
	
		for(int l = 0; l<anzIt; l++)
		{
			for(int i =0; i<n; i++)
			{
				double sum1 = 0.0;
				for(int j=0; j<=i-1; j++)
				{
					sum1+=(float)A[i][j]*Xneu[j];	
				}
				
				double sum2=0.0;
				for(int j =i+1; j<n; j++)
				{
					sum2+=A[i][j]*Xalt[j];
				}
				Xneu[i] = (float)(-sum1-sum2+c[i])/A[i][i];	
			}
			
			Xalt = Xneu;
			System.out.print(l<10 ? " "+l+":" : ""+l+":");	
			printTranspose(Xneu);
			System.out.print("");
		}
	}
	
	
	
	public static void JakobiVerf()
	{
		getInfoJakobi();
		System.out.println("\ngegebene Matrix A: ");
		print(A);
		System.out.println("\nVektor b mit den Resultaten: ");
		print(c);
		
		double [][]Tj = new double[n][n];
		
		for(int i = 0; i<n; i++)
		{
			for(int k = 0; k<n; k++)
			{
				Tj[i][k] = (double)-A[i][k]/A[i][i];
			}
			c[i] = (float) c[i]/A[i][i];
			Tj[i][i] = 0;
		}
		System.out.println("\nMatrix Tj: ");
		print(Tj);
		System.out.println("\nveränderten ResultatenVektor c: ");
		print(c);
		System.out.println("\n x-Vektoren:");
		Xalt = c;
		for(int j = 0; j<anzIt && err<= maxiDiff; j++)
		{
			Xneu = matrixMulti(Tj,Xalt);
			Xneu = vectorAdd(Xneu, c);
			maxiDiff=0;
			System.out.print(j<10 ? " "+j+":" : ""+j+":");
			printTranspose(Xneu);
			
			for(int m = 0; m<n; m++)
			{
				maxiDiff = Math.max(maxiDiff, Math.abs(Xneu[m]-Xalt[m]) );
			}
			Xalt = Xneu;
		}
		System.out.println("\nx-Vektor mit den Lösungen:");
		print(Xalt);
		System.out.println("\ncheck, auf Richtigkeit: A*x=b");
		print(matrixMulti(A,Xalt));
	}
	
	// Gauss-Seidel-Verfahren
	public static void GaussSeidel()
	{
		getInfoSeidel();
		System.out.println("\ngegebene Matrix A: ");
		print(A);
		System.out.println("\nVektor b mit den Resultaten: ");
		print(c);
		
		double [][]Tj = new double[n][n];
		
		for(int i = 0; i<n; i++)
		{
			for(int k = 0; k<n; k++)
			{
				Tj[i][k] = (double)-A[i][k]/A[i][i];
			}
			c[i] = (float) c[i]/A[i][i];
			Tj[i][i] = 0;
		}
		System.out.println("\nMatrix Tj: ");
		print(Tj);
		System.out.println("\nveränderten ResultatenVektor c: ");
		print(c);
		System.out.println("\n x-Vektoren:");
		for(int j = 0; j<anzIt && err<= maxiDiff; j++)
		{
			for(int i=0; i<n; i++)
			{
				double sum = 0;
				for(int k = 0;k<n; k++)
				{
					sum+=Tj[i][k]*Xneu[k];
				}
				Xneu[i] = c[i] + sum;
			}
			maxiDiff=0;
			System.out.print(j<10 ? " "+j+":" : ""+j+":");
			printTranspose(Xneu);
			
			for(int m = 0; m<n; m++)
			{
				maxiDiff = Math.max(maxiDiff, Math.abs(Xneu[m]-Xalt[m]) );
				Xalt[m] = Xneu[m];
			}
		}
		System.out.println("\nx-Vektor mit den Lösungen:");
		print(Xalt);
		System.out.println("\ncheck, auf Richtigkeit: A*x=b");
		print(matrixMulti(A,Xalt));
	}
	
	private static void print(double[][] A)
	{
		for (int i = 0; i<A[0].length; i++)
		{
			System.out.print(" | ");
			for(int j = 0; j<A[0].length; j++)
			{
				InOut.print(A[i][j], vorKomma, nachKomma);
				System.out.print("  ");
			}
			System.out.println("| ");
		}	
	}
	private static void print(double[] A)
	{
		
		for(int j = 0; j<A.length; j++)
		{
			System.out.print(" | ");
			InOut.print(A[j], vorKomma, nachKomma);
			System.out.println("  | ");
		}
	}
		
	private static void printTranspose(double[] A)
	{
		System.out.print(" |");
		for(int j = 0; j<A.length; j++)
		{	
			System.out.print(" ");
			InOut.print(A[j], vorKomma, nachKomma);	
			System.out.print(" ");
		}
		System.out.println(" | ");
	}
	
	private static double[] vectorAdd(double[] a, double[] b)
	{
		for(int i = 0; i<a.length; i++)
		{
			a[i] +=b[i];
		}
		return a;
	}
	
	private static double[] matrixSub(double[] a, double[] b)
	{
		for(int i = 0; i<a.length; i++)
		{
			a[i] -=b[i];
		}
		return a;
	}
	
		private static double[] matrixMulti(double[][] a, double[] b)
	{
		double[]res = new double[b.length];
		for(int i = 0; i<b.length; i++)
		{
			double sum = 0;
			for(int m=0; m<b.length; m++)
			{
				sum+= a[i][m]*b[m];
			}
			res[i]=sum;
			
		}
		return res;
	}
	
	private static void getInfoJakobi()
	{
		String s="";
		s+="\n***************************************************************";
		s+="\n*                                                             *";
		s+="\n*          Jakobi-Verfahren zum Lösen von GLS                 *";
		s+="\n*                                                             *";
		s+="\n*   Autor: Remo Waller                                        *";
		s+="\n*                                                             *";
		s+="\n*   Mit Hilfe dieses Programms lässt sich eine Matrix A       *";
		s+="\n*   lösen...                                                  *";
		s+="\n*                                                             *";
		s+="\n***************************************************************";
		
		System.out.println(s);
	}
	private static void getInfoSeidel()
	{
		String s="";
		s+="\n***************************************************************";
		s+="\n*                                                             *";
		s+="\n*        Gauss-Seidel-Verfahren zum Lösen von GLS             *";
		s+="\n*                                                             *";
		s+="\n*   Autor: Remo Waller                                        *";
		s+="\n*                                                             *";
		s+="\n*   Mit Hilfe dieses Programms lässt sich eine Matrix A       *";
		s+="\n*   lösen...                                                  *";
		s+="\n*                                                             *";
		s+="\n***************************************************************";
		
		System.out.println(s);
	}
}