/*
 * 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 SOR-Verfahren. 
 * 	Numerik-Buch Seite 312. Kapitel 7.5
 *
 */

class SOR
{
	static int n = 4;							// Matrizengrösse
	private static final int  vorKomma = 2;		// Formatierung
	private static final int  nachKomma = 7;
	
	private static double[][]A = { {10,1,-2,0 } ,  {1,10,-1,3}, { -2,-1,8,-1}, {0,3,-1,5} };
	private static double[]  c = { 6,25,-11,-11};
	private static double[] Xalt = new double[n];
	private static double[] Xneu = new double[n];
	private static double[] X = new double[n];
	private static double maxiDiff=1000;			// so belassen
	private static int anzIt = 25;					// #Iterationen
	private static double err  = Math.pow(10, -5);	// Fehlerabweichung
	private static double omega = 1.25;				// Gewichtung

	public static void main(String [] args)
	{
		//SorKomplex();
		SorEinfach();
	}
	
	public static void SorEinfach()
	{
		getInfoSOR();
		System.out.println("\ngegebene Matrix A: ");
		print(A);
		System.out.println("\nVektor b mit den Resultaten: ");
		print(c);
		System.out.println("");
		// X-Vektoren mit 1er initialisieren:
		for(int i=0; i<n; i++)
		{
			X[i] = 1;
		}
		
		System.out.print(" 0:");	
		printTranspose(X);
		for(int k = 1; k<anzIt; k++)
		{
			for(int i=0; i<n; i++)
			{
				double sum1 = 0.0;
				for(int j=0; j<=i-1; j++)
				{
					sum1+=A[i][j]*X[j];
				}
				double sum2=0.0;
				for(int j=i+1; j<n; j++)
				{
					sum2+=A[i][j]*X[j];
				}
				
				X[i] = (1-omega)*X[i] + omega/A[i][i] *(c[i]-sum1-sum2);
				
			}
			System.out.print(k<10 ? " "+k+":": ""+k+":");	
			printTranspose(X);
		
		}
		
		System.out.println("\nx-Vektor mit den Lösungen:");
		print(X);
		System.out.println("\ncheck, auf Richtigkeit: A*x=b");
		print(matrixMulti(A,X));
	}
	
	
	
	
	public static void SorKomplex()
	{
		getInfoSOR();
		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 i=0; i<n; i++)
		{
			for(int j=0; j<n; j++)
			{
				Tj[i][j] = omega *Tj[i][j];
				Tj[i][i] = 1-omega;
			}
			c[i] = omega*c[i];
		}
		
		//Xneu und Xalt mit 1 füllen;
		for(int i=0; i<n; i++)
		{
			Xneu[i]=1;
			Xalt[i]=1;
		}
		System.out.print(" 0:");	
		printTranspose(Xneu);
	
		for(int j=1; j<anzIt && err <= maxiDiff; j++)
		{
			for(int i=0;i<n;i++)
			{
				double sum=0.0;
				for(int k=0; k<n; k++)
				{	
					sum+=Tj[i][k] * Xneu[k];
				}
				Xneu[i] = c[i]+sum;
			}
			System.out.print(j<10 ? " "+j+":" : ""+j+":");
			printTranspose(Xneu);
			maxiDiff=0;
			for(int m = 0; m<n; m++)
			{
				maxiDiff = Math.max(maxiDiff, Math.abs(Math.abs(Xneu[m])-Math.abs(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[] vectorSub(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 getInfoSOR()
	{
		String s="";
		s+="\n***************************************************************";
		s+="\n*                                                             *";
		s+="\n*              SOR-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);
	}
}