Metoda QR obliczania wartości własnych macierzy

0

Jako że nie ma działu dla metod numerycznych umieszczam zadanie tutaj
Próbowałem napisać samodzielnie program realizujący tę metodę
Co mam do tej pory
Sprowadzenie macierzy do postaci Hessenberga ale tylko za pomocą eliminacji Gaussa
bo była ona dobrze opisana w jednej z książek do metod numerycznych
Wolałbym jednak użyć do tej redukcji odbić Householdera bo eliminacja Gaussa bywa niestabilna numerycznie
Czym jest postać Hessenberga?
Macierz A jest w postaci Hessenberga jeżeli można ją zapisać w następujący sposób
A = U+T , gdzie U to macierz trójkątna górna a T macierz trójdiagonalna
Rozkład QR zrealizowałem za pomocą mnożenia przez macierze obrotów
Rozpisałem sobie mnożenie przez macierze obrotów i okazało się że lewostronne mnożenie modyfikuje tylko dwa wiersze
a prawostronne mnożenie modyfikuje tylko dwie kolumny
(Mnożymy lewostronnie macierz A przez macierze obrotów aby dostać macierz R
Mnożymy prawostronnie macierz I przez te same macierze obrotów aby dostać macierz Q)
Mnożenie macierzy niby łatwe - zastosowanie wzorku - trzy pętle ale aby dobrze działało musiałem macierz skopiować
Na razie algorytm wykonuje tylko z góry określoną liczbę iteracji
Podstawowa metoda QR wygląda następująco
A_{k} = Q_{k}R_{k}
A_{k+1} = R_{k}Q_{k}
Nietrudno pokazać że metoda ta tworzy nam ciąg macierzy podobnych do macierzy A

Jeżeli metoda ta jest zbieżna do postaci Schura to stosunkowo łatwo odczytać wartości własne
Macierz w postaci Schura jest macierzą trójkątną (dla macierzy o elementach zespolonych)
oraz taką macierzą w której na przekątnej występują co najwyżej bloki 2x2 , poniżej tej blokowej przekątnej występują zera
a powyżej dowolna liczba rzeczywista
(te bloki 2x2 występują tylko jeżeli wartości własne z nich policzone są zespolone a cała macierz ma tylko elementy rzeczywiste)

Problem w tym że ta metoda w podstawowej wersji nie zawsze jest zbieżna do postaci Schura
a nawet jeśli jest zbieżna to dość często jest zbieżna bardzo wolno

No i teraz jakie wybrać przesunięcie i jak je zrealizować?
Jak zrealizować deflację
Co ze zbieżnością dla wielokrotnych wartości własnych
Jaki warunek stopu , inny niż maksymalna liczba iteracji ?
A i jeszcze jedno chciałbym uniknąć arytmetyki zespolonej

using System;
using System.IO;
using System.Globalization;
namespace NamespaceName
{
	public class ClassName
	{
		const int maxiter = 1000;
		const double eps = 1e-12;
		public static void PrintMatrix(int m,int n,double[,] A)
		{
			NumberFormatInfo nfi = new NumberFormatInfo();
			nfi.NumberDecimalDigits = 12;
			for(int i = 0; i < m; i++)
			{
				for(int j = 0; j < n; j++)
				  Console.Write("{0} ,",A[i,j].ToString("N",nfi));
			    Console.WriteLine();
			}
			Console.WriteLine();
		}
		public static void PrintMatrix(StreamWriter sw,int m,int n,double[,] A)
		{
			NumberFormatInfo nfi = new NumberFormatInfo();
			nfi.NumberDecimalDigits = 12;
			for(int i = 0; i < m; i++)
			{
				for(int j = 0; j < n; j++)
				  sw.Write("{0} ",A[i,j].ToString("N",nfi));
			    sw.WriteLine();
			}
			sw.WriteLine();
		}
		public static double Hypot(double a,double b)
		{
			double absa,absb;
			absa = Math.Abs(a);
			absb = Math.Abs(b);
			if(absa > absb) return absa * Math.Sqrt(1 + ((double) absb / absa) * ((double) absb / absa));
			else return (absb == 0 ? 0 : absb * Math.Sqrt(1 + ((double) absa / absb) * ((double) absa / absb)));
		}
		public static void ToHessenberg(int n,double[,] A)
		{
			for(int i = 0; i < n - 2;i++)
			{
				int k = i + 1;
				double maxA = Math.Abs(A[k,i]);
				for(int j = i + 1; j < n; j++)
					if(Math.Abs(A[j,i]) > maxA)
					{
						k = j;
						maxA = Math.Abs(A[k,i]);
					}
				if(maxA > 0)
				{
					for(int j = 0; j < n; j++)
					{
						double temp = A[k,j];
						A[k,j] = A[i + 1,j];
						A[i + 1,j] = temp;
					}
					for(int j = 0; j < n;j++)
					{
						double temp = A[j,k];
						A[j,k] = A[j,i + 1];
						A[j,i + 1] = temp;
					}
					for(int j = i + 2; j < n; j++)
					{
						double m = (double) A[j,i] / A[i + 1,i];
						for(int l = 0; l < n; l++)
							A[j,l] -= m * A[i + 1,l];
						for(int l = 0;l < n;l++)
							A[l,i + 1] += m * A[l,j]; 
					}
				}
			}
		}
		public static void QR_Givens(int m,int n,double[,] A,double[,] Q)
		{
			for(int i = 0; i < m; i++)
				for(int j = 0;j < m;j++)
					Q[i,j] = (i == j ? 1 : 0);
				int min = (m < n ? m : n);
				for(int i = 0; i < min; i++)
					for(int j = i + 1; j < m; j++)
						if(A[j,i] != 0)
						{
							double r = Hypot(A[i,i],A[j,i]);
							double c = (double) A[i,i] / r;
							double s = (double) A[j,i] / r;
							for(int k = 0; k < n; k++)
							{
								double temp = A[i,k];
								A[i,k] = c * A[i,k] + s * A[j,k];
								A[j,k] = -s * temp + c * A[j,k];
							}
							for(int k = 0;k < m;k++)
							{
								double temp = Q[k,i];
								Q[k,i] = c * Q[k,i] + s * Q[k,j];
								Q[k,j] = -s * temp + c * Q[k,j];
							}
						}
				
		}
		public static void CopyMatrix(int m,int n, double[,] A,double[,] B)
		{
			for(int i = 0; i < m; i++)
				for(int j = 0; j < n; j++)
					B[i,j] = A[i,j];
		}
		public static void MultiplyMatrix(int m,int n,int p,double[,] A,double[,] B,double[,] C)
		{
			for(int i = 0; i < m; i++)
				for(int k = 0; k < p; k++)
				{
					C[i,k] = 0;
					for(int j =0; j < n; j++)
						C[i,k] += A[i,j] * B[j,k];
				}
		}
		public static void Main(string[] args)
		{
			Console.Clear();
			char esc;
			double[,] A,Q,R;
			int n;
			string path;
			Console.WriteLine("Podaj sciezke do pliku do ktorego chcesz zapisac wynik");
			path = Console.ReadLine();
			using(StreamWriter sw = new StreamWriter(path,true))
			{
				do
				{
					Console.WriteLine("Podaj stopień macierzy ktorej wartosci wlasne chcesz policzyc");
					int.TryParse(Console.ReadLine(),out n);
					A = new double[n,n];
					R = new double[n,n];
					Q = new double[n,n];
					for(int i = 0;i < n;i++)
						for(int j = 0;j < n;j++)
						{
							Console.Write("A[{0},{1}]=",i,j);
							double.TryParse(Console.ReadLine(),out A[i,j]);
						}
					Console.WriteLine("Wczytana macierz A");
					sw.WriteLine("Wczytana macierz A");		
					PrintMatrix(n,n,A);
					PrintMatrix(sw,n,n,A);
					ToHessenberg(n,A);
					Console.WriteLine("Macierz A po sprowadzeniu do postaci Hessenberga");
					PrintMatrix(n,n,A);
					sw.WriteLine("Macierz A po sprowadzeniu do postaci Hessenberga");
					PrintMatrix(sw,n,n,A);
					for(int i = 0;i < maxiter; i++)
					{
						QR_Givens(n,n,A,Q);
						CopyMatrix(n,n,A,R);
						MultiplyMatrix(n,n,n,R,Q,A);
					}
					Console.WriteLine("Macierz A po iteracyjnym sprowadzeniu do postaci Schura");
					sw.WriteLine("Macierz A po iteracyjnym sprowadzeniu do postaci Schura");
					PrintMatrix(n,n,A);
					PrintMatrix(sw,n,n,A);
					Console.WriteLine("Przyblizone wartosci wlasne macierzy A");
					sw.WriteLine("Przyblizone wartosci wlasne macierzy A");
					int k = 0;
					NumberFormatInfo nfi = new NumberFormatInfo();
					nfi.NumberDecimalDigits = 12;
					while(k < n)
					{
						if(k + 1 < n && Math.Abs(A[k+1,k]) > eps)
						{
							double p = 0.5 * (A[k,k] + A[k + 1,k + 1]);
							double q = A[k,k] * A[k + 1,k + 1] - A[k,k + 1] * A[k + 1,k];
							double d = Math.Sqrt(Math.Abs(q - p * p));
							Console.WriteLine("x[{0}]={1} - {2}i",k,p.ToString("N",nfi),d.ToString("N",nfi));
							Console.WriteLine("x[{0}]={1} + {2}i",k+1,p.ToString("N",nfi),d.ToString("N",nfi));
							sw.WriteLine("x[{0}]={1} - {2}i",k,p.ToString("N",nfi),d.ToString("N",nfi));
							sw.WriteLine("x[{0}]={1} + {2}i",k+1,p.ToString("N",nfi),d.ToString("N",nfi));
							k += 2;
						}
						else
						{
							Console.WriteLine("x[{0}]={1}",k,A[k,k].ToString("N",nfi));
							sw.WriteLine("x[{0}]={1}",k,A[k,k].ToString("N",nfi));
							k++;
						}
					}
					esc = (char) Console.ReadKey().Key;
				}
				while(esc != (char) ConsoleKey.Escape);
			}
		}
	}
}

0
nowy121105 napisał(a):

Jako że nie ma działu dla metod numerycznych umieszczam zadanie tutaj
Próbowałem napisać samodzielnie program realizujący tę metodę
Co mam do tej pory
Sprowadzenie macierzy do postaci Hessenberga ale tylko za pomocą eliminacji Gaussa
bo była ona dobrze opisana w jednej z książek do metod numerycznych
Wolałbym jednak użyć do tej redukcji odbić Householdera bo eliminacja Gaussa bywa niestabilna numerycznie

Szukałeś jakichkolwiek przykładów takich realizacji? Znasz je? Masz jakiś tekst który realizuje to podejście?

Czym jest postać Hessenberga?
Macierz A jest w postaci Hessenberga jeżeli można ją zapisać w następujący sposób
A = U+T , gdzie U to macierz trójkątna górna a T macierz trójdiagonalna
Rozkład QR zrealizowałem za pomocą mnożenia przez macierze obrotów
Rozpisałem sobie mnożenie przez macierze obrotów i okazało się że lewostronne mnożenie modyfikuje tylko dwa wiersze
a prawostronne mnożenie modyfikuje tylko dwie kolumny
(Mnożymy lewostronnie macierz A przez macierze obrotów aby dostać macierz R
Mnożymy prawostronnie macierz I przez te same macierze obrotów aby dostać macierz Q)
Mnożenie macierzy niby łatwe - zastosowanie wzorku - trzy pętle ale aby dobrze działało musiałem macierz skopiować
Na razie algorytm wykonuje tylko z góry określoną liczbę iteracji
Podstawowa metoda QR wygląda następująco
A_{k} = Q_{k}R_{k}
A_{k+1} = R_{k}Q_{k}
Nietrudno pokazać że metoda ta tworzy nam ciąg macierzy podobnych do macierzy A

Jeżeli metoda ta jest zbieżna do postaci Schura to stosunkowo łatwo odczytać wartości własne
Macierz w postaci Schura jest macierzą trójkątną (dla macierzy o elementach zespolonych)
oraz taką macierzą w której na przekątnej występują co najwyżej bloki 2x2 , poniżej tej blokowej przekątnej występują zera
a powyżej dowolna liczba rzeczywista
(te bloki 2x2 występują tylko jeżeli wartości własne z nich policzone są zespolone a cała macierz ma tylko elementy rzeczywiste)

Problem w tym że ta metoda w podstawowej wersji nie zawsze jest zbieżna do postaci Schura

A czy jesteś zmuszony korzystać akurat z QR? Jaka jest twa motywacja by rzucać się akurat na tą metodę, skoro masz tyle zatrzeżeń?

a nawet jeśli jest zbieżna to dość często jest zbieżna bardzo wolno

No tak wygląda świat metod numerycznych, różna dokładność, różna prędkość działania. Nie każda metoda do wszystkiego się nadaje.

No i teraz jakie wybrać przesunięcie i jak je zrealizować?

Ummm... zgodnie z algorytmem? Masz niejasny opis jak to wykonać w materiale z ktrego korzystasz? Skorzystanie z QR bez przesunięcia będzie OK?

Jak zrealizować deflację

A jakie metody rozpatrujesz? Czy pytasz ogólnie jaka jest definicja deflacji? Co stanowi konkretnie problem?

Co ze zbieżnością dla wielokrotnych wartości własnych

W jakim kontekście pytasz? Szukasz algorytmu który się nimi interesuje?

Jaki warunek stopu , inny niż maksymalna liczba iteracji ?

Stopu w Householderze? Czy deflacji? W QR? Czy w czym?

A i jeszcze jedno chciałbym uniknąć arytmetyki zespolonej

W którym momencie widzisz potrzebę uciekania się do arytmetyki zespolonej?

Czytając ten post w zasadzie nie wiem czy problemem jest że chcesz liczyć coś na danych, które średnio się nadają do metody którą chcesz stosować, czy też problemem jest niejasność co do kroków jakie należy wykonać, czy po prostu korzystasz z jakiegoś kijowego opisu metody z książki która się nadaje bardziej na podpórkę do biurka niż materiał edukacyjny, czy też jeszcze coś innego. W twym poście jest wiele pytań i niewiele uzasadnień czy wyjaśnień, że nie wspomnę iż ciężko się zorientować czy pytanie dotyczy Householdera, deflacji, QR czy czegoś jeszcze.

Nie wiem czytając twój post czy chcesz rozmawiać o implementacji czy o algebrze liniowej czy o tym i o tym. Chcesz implementować QR, to algorytm jest opisany w dziesiątkach publikacji. Chcesz tworzyć własny algorytm, to na jakimś forum matematycznym zapewne znajdziesz większą publikę kompetentną w te materii.

Pozwolę więc sobie zasugerować lektury:

"The Householder transformation in numerical linear algebra, John Kerl, February 3, 2008" https://johnkerl.org/doc/hh.pdf

"Module for The QR Method for Eigenvalues" https://web.archive.org/web/20081209042103/http://math.fullerton.edu/mathews/n2003/QRMethodMod.html

"The unshifted QR algorithm" https://pi.math.cornell.edu/~web6140/TopTenAlgorithms/QRalgorithm.html

Wszelakie dekompozycje, szukanie wartości i wektorów własnych, transpozycje, deflacje i inne cuda na kiju z algebry liniowej są tematem mocno oklepanym w informatyce i jest kupa lepszych lub gorszych publikacji na ich temat po angielsku do znalezenia na necie o ich implementacji w oprogramowaniu. Jest też masa bibliotek, których kod można sobie przeglądać na GitHub czy SourceForge, które je implementują.

0

A czy jesteś zmuszony korzystać akurat z QR?

No bo to dobry algorytm i działa dla każdej macierzy
a zastrzeżenia mam tylko do podstawowej wersji algorytmu

Ummm... zgodnie z algorytmem? Masz niejasny opis jak to wykonać w materiale z ktrego korzystasz? Skorzystanie z QR bez przesunięcia będzie OK?...

Problem w tym że w żadnym materiale nie było objaśniony sposób wyboru dobrego przesunięcia , nawet w tych materiałach co podałeś nic o tym nie ma

Stopu w Householderze? Czy deflacji? W QR? Czy w czym?

No w QR gdybyś uważnie czytał to byś wiedział

W jakim kontekście pytasz? Szukasz algorytmu który się nimi interesuje?

No chodzi o to że metoda QR jest bardzo wolno zbieżna w przypadku wielokrotnych wartości własnych a chciałem ten przypadek także uwzględnić

Czytając ten post w zasadzie nie wiem czy problemem jest że chcesz liczyć coś na danych, które średnio się nadają do metody którą chcesz stosować, czy też problemem jest niejasność co do kroków jakie należy wykonać, czy po prostu korzystasz z jakiegoś kijowego opisu metody z książki która się nadaje bardziej na podpórkę do biurka niż materiał edukacyjny, czy też jeszcze coś innego..

Problemem jest właśnie niejasność co do kroków jakie należy wykonać a także to że w książkach znajdują się kijowe opisy

Jak użyć metody odbić Householdera do redukcji macierzy do postaci Hessenberga
Mile widziany zrozumiały pseudokod aby łatwiej było napisać funkcję
W tych kijowych książkach jest pokazane mnożenie przez macierze a to jest podejście dobre dla matematyka a nie tego który chciałby taką procedurę zaprogramować

Jak mogłaby wyglądać deflacja

0

Puszczę mimo uszu twoje teksty "gdybyś czytał uważnie" uznając, że masz Aspergera (jak nie masz, to mnie nie wyprowadzaj z błędu, bo to ci bardziej zaszkodzi niż pomoże).

Spora ilość starszych książek zakłada, że implementujesz to w FORTRANie. Co istotnie bywa upierdliwe. Innym problemem jest, że są pisane dla obcykanych w aglebrę liniową matematyków którzy są po normalnym kursie algebry i widzą sporo rzeczy. Faktem jest, że jakość nauczania algebry liniowej w Polsce d**y nie urywa. Wiem, bo jak przyszedłem na infę na UJ na FAiS to spotkałem cały desant spadochroniarzy z "zaprzyjaźnionego" [taki dowcip dla kumatych w temacie czemu na UJ są informatyki na dwóch wydziałach] wydziału matematyki i informatyki. Bo większość roku oblała na tamtym wydziale algebrę i nie zaliczyła przez to roku. Potem wielcy intelektualiści, elita polskiej oświaty wyższej i kwiat matematyki europejskiej zorientowała się gdzieś tak na wakacjach, że w związku z ilością studentów, która oblała egzamin nie będzie możliwe formalnie prowadzenie przez tą jakże wybitną placówkę drugiego roku nakierunku informatyka. xD No ale tak jest jak się nie ogarnia w pedagogikę i uważa, że studenci są tylko po to aby ich egzaminować a uczyć się powinni zupełnie sami, ewentualnie by potem szczycic się wydział mógł faktem, że studenci mają osiągnięcia mimo niemal zerowego wkładu w ich sukces kadry wydziału. xD Dobra, porobiłem sobie jaja z byłej uczelni, to teraz wróćmy do tematu.

Pozwoliłem sobie wyszukać wideo gdzie w miarę się starają przekazać o co kaman. Ostatni zdaje się porusza w miarę ścieżkę która cię interesuje. Jeśli dalej będą niejsaności z chęcią poszukam keszcze innych materiałów, tylko przekaż mi co jest konkretnie niejasne. Pisz jak dla debila. Wtedy będzie pewność, że zrozumiem. ;)










0

Co do przesunięcia to:
Iloraz Rayleigha nie daje gwarancji zbieżności a poza tym wektor dla którego liczymy ten iloraz powinien dążyć do wektora własnego
Przesunięcie Wilkinsona wydaje się działać tylko dla macierzy symetrycznych
Zastanawiałem się nad podwójnym przesunięciem

  • dwa przesunięcia na iterację, jako przesunięcia używamy dwóch liczb rzeczywistych lub jednej pary sprzężonych liczb zespolonych
    tylko jak je zrealizować bez psucia sobie postaci Hessenberga
    Co do deflacji to myślałem aby funkcje realizujące metodę QR działały na wybranym bloku macierzy zamiast na całej macierzy
    tylko jak to zrealizować bez psucia sobie postaci Hessenberga
    Znalazłem też gotowca
using System;
using System.IO;
using System.Globalization;
namespace NamespaceName
{
	public static class nrutils
	{
		public static int imax(int a,int b)
		{
			int imaxarg1,imaxarg2;
			imaxarg1 = a;
			imaxarg2 = b;
			return (imaxarg1 > imaxarg2 ?imaxarg1:imaxarg2);
		}
		public static double sign(double a,double b)
		{
			return (b >= 0.0 ? Math.Abs(a):-Math.Abs(a));
		}
		public static void swap(ref double g, ref double h)
		{
			double y = g;
			g = h;
			h = y;
		}
	}
	public class ClassName
	{
		const double RADIX = 2.0;
		public static void balanc(double[,] a, int n)
		{
			int last,j,i;
			double s,r,g,f,c,sqrdx;

			sqrdx=RADIX*RADIX;
			last=0;
			while (last == 0) {
				last=1;
				for (i=1;i<=n;i++) {
					r=c=0.0;
					for (j=1;j<=n;j++)
						if (j != i) {
							c += Math.Abs(a[j,i]);
							r += Math.Abs(a[i,j]);
						}
					if (c != 0 && r != 0) {
						g=r/RADIX;
						f=1.0;
						s=c+r;
						while (c<g) {
							f *= RADIX;
							c *= sqrdx;
						}
						g=r*RADIX;
						while (c>g) {
							f /= RADIX;
							c /= sqrdx;
						}
						if ((c+r)/f < 0.95*s) {
							last=0;
							g=1.0/f;
							for (j=1;j<=n;j++) a[i,j] *= g;
							for (j=1;j<=n;j++) a[j,i] *= f;
						}
					}
				}
			}
		}
		public static void elmhes(double[,] a, int n)
		{
			int m,j,i;
			double y,x;

			for (m=2;m<n;m++) {
				x=0.0;
				i=m;
				for (j=m;j<=n;j++) {
					if (Math.Abs(a[j,m-1]) > Math.Abs(x)) {
						x=a[j,m-1];
						i=j;
					}
				}
				if (i != m) {
					for (j=m-1;j<=n;j++) nrutils.swap(ref a[i,j],ref a[m,j]);
					for (j=1;j<=n;j++) nrutils.swap(ref a[j,i],ref a[j,m]);
				}
				if (x != 0) {
					for (i=m+1;i<=n;i++) {
						if ((y=a[i,m-1]) != 0.0) {
							y /= x;
							a[i,m-1]=y;
							for (j=m;j<=n;j++)
								a[i,j] -= y*a[m,j];
							for (j=1;j<=n;j++)
								a[j,m] += y*a[j,i];
						}
					}
				}
			}
		}
		public static void hqr(double[,] a, int n, double[] wr, double[] wi)
		{
			int nn,m,l,k,j,its,i,mmin;
			double z,y,x,w,v,u,t,s,r=0,q=0,p=0,anorm;

			anorm=0.0;
			for (i=1;i<=n;i++)
				for (j=nrutils.imax(i-1,1);j<=n;j++)
					anorm += Math.Abs(a[i,j]);
			nn=n;
			t=0.0;
			while (nn >= 1) {
				its=0;
				do {
					for (l=nn;l>=2;l--) {
						s=Math.Abs(a[l-1,l-1])+Math.Abs(a[l,l]);
						if (s == 0.0) s=anorm;
						if ((double)(Math.Abs(a[l,l-1]) + s) == s) {
							a[l,l-1]=0.0;
							break;
						}
					}
					x=a[nn,nn];
					if (l == nn) {
						wr[nn]=x+t;
						wi[nn--]=0.0;
					} else {
						y=a[nn-1,nn-1];
						w=a[nn,nn-1]*a[nn-1,nn];
						if (l == (nn-1)) {
							p=0.5*(y-x);
							q=p*p+w;
							z=Math.Sqrt(Math.Abs(q));
							x += t;
							if (q >= 0.0) {
								z=p+nrutils.sign(z,p);
								wr[nn-1]=wr[nn]=x+z;
								if (z != 0) wr[nn]=x-w/z;
								wi[nn-1]=wi[nn]=0.0;
							} else {
								wr[nn-1]=wr[nn]=x+p;
								wi[nn-1]= -(wi[nn]=z);
							}
							nn -= 2;
						} else {
							if (its == 30) Console.WriteLine("Too many iterations in hqr");
							if (its == 10 || its == 20) {
								t += x;
								for (i=1;i<=nn;i++) a[i,i] -= x;
								s=Math.Abs(a[nn,nn-1])+Math.Abs(a[nn-1,nn-2]);
								y=x=0.75*s;
								w = -0.4375*s*s;
							}
							++its;
							for (m=(nn-2);m>=l;m--) {
								z=a[m,m];
								r=x-z;
								s=y-z;
								p=(r*s-w)/a[m+1,m]+a[m,m+1];
								q=a[m+1,m+1]-z-r-s;
								r=a[m+2,m+1];
								s=Math.Abs(p)+Math.Abs(q)+Math.Abs(r);
								p /= s;
								q /= s;
								r /= s;
								if (m == l) break;
								u=Math.Abs(a[m,m-1])*(Math.Abs(q)+Math.Abs(r));
								v=Math.Abs(p)*(Math.Abs(a[m-1,m-1])+Math.Abs(z)+Math.Abs(a[m+1,m+1]));
								if ((double)(u+v) == v) break;
							}
							for (i=m+2;i<=nn;i++) {
								a[i,i-2]=0.0;
								if (i != (m+2)) a[i,i-3]=0.0;
							}
							for (k=m;k<=nn-1;k++) {
								if (k != m) {
									p=a[k,k-1];
									q=a[k+1,k-1];
									r=0.0;
									if (k != (nn-1)) r=a[k+2,k-1];
									if ((x=Math.Abs(p)+Math.Abs(q)+Math.Abs(r)) != 0.0) {
										p /= x;
										q /= x;
										r /= x;
									}
								}
								if ((s=nrutils.sign(Math.Sqrt(p*p+q*q+r*r),p)) != 0.0) {
									if (k == m) {
										if (l != m)
										a[k,k-1] = -a[k,k-1];
									} else
										a[k,k-1] = -s*x;
									p += s;
									x=p/s;
									y=q/s;
									z=r/s;
									q /= p;
									r /= p;
									for (j=k;j<=nn;j++) {
										p=a[k,j]+q*a[k+1,j];
										if (k != (nn-1)) {
											p += r*a[k+2,j];
											a[k+2,j] -= p*z;
										}
										a[k+1,j] -= p*y;
										a[k,j] -= p*x;
									}
									mmin = nn<k+3 ? nn : k+3;
									for (i=l;i<=mmin;i++) {
										p=x*a[i,k]+y*a[i,k+1];
										if (k != (nn-1)) {
											p += z*a[i,k+2];
											a[i,k+2] -= p*r;
										}
										a[i,k+1] -= p*q;
										a[i,k] -= p;
									}
								}
							}
						}
					}
				} while (l < nn-1);
			}
		}
		public static void PrintMatrix(int m,int n,double[,] a)
		{
			for(int i = 1; i <= m;i++)
			{
				for(int j = 1; j <= n;j++)
					Console.Write("{0} ",a[i,j]);
				Console.WriteLine();
			}
			Console.WriteLine();
		}
		public static void Main(string[] args)
		{
			char esc; 
			string path;
			int deg;
			double[] c;
			double[,] a;
			double[] wr,wi;
			NumberFormatInfo nfi = new NumberFormatInfo();
			nfi.NumberDecimalDigits = 12;
			Console.WriteLine("Obliczanie przyblizonych pierwiastkow wielomianu");
			Console.WriteLine("metoda wartosci wlasnych macierzy stowarzyszonej");
			Console.WriteLine("Podaj sciezke do pliku w ktorym chcesz zapisac wynik");
			path = Console.ReadLine();
			using(StreamWriter sw = new StreamWriter(path,true))
			{	
				do
				{
					Console.WriteLine("Podaj stopień wielomianu");
					int.TryParse(Console.ReadLine(),out deg);
					c = new double[deg+1];
					a = new double[deg+1,deg+1];
					wr = new double[deg+1];
					wi = new double[deg+1];
					for(int i=deg;i>=0;i--)
					{
						Console.Write("c[{0}]=",i);
						double.TryParse(Console.ReadLine(),out c[i]);
						if(c[i]<0)
							sw.Write("{0} * x^{1}",c[i],i);
						else
							sw.Write("+{0} * x^{1}",c[i],i);
					}
					sw.WriteLine("=0");
					for(int i=1;i<=deg;i++)
						a[1,i] = (double)(-c[deg-i])/c[deg];
					for(int i=2;i <= deg;i++)
						for(int j=1;j <= deg;j++)
							a[i,j] = (j + 1 == i ? 1 : 0);
					hqr(a,deg,wr,wi);
					Console.WriteLine("Przyblizone pierwiastki wielomianu");
					sw.WriteLine("Przyblizone pierwiastki wielomianu");
					for(int i=1;i <= deg;i++)
						if(wi[i] < 0)
						{
							Console.WriteLine("x[{0}]={1} - {2}*i",i,wr[i].ToString("N",nfi),(-wi[i]).ToString("N",nfi));
							sw.WriteLine("x[{0}]={1} - {2}*i",i,wr[i].ToString("N",nfi),(-wi[i]).ToString("N",nfi));
						}
						else
						{
							Console.WriteLine("x[{0}]={1} + {2}*i",i,wr[i].ToString("N",nfi),wi[i].ToString("N",nfi));
							sw.WriteLine("x[{0}]={1} + {2}*i",i,wr[i].ToString("N",nfi),wi[i].ToString("N",nfi));
						}
					esc = (char)Console.ReadKey().Key;
				}
				while(esc != (char)ConsoleKey.Escape);
			}
		}
	}
}

Tylko o co tutaj chodzi ?
Jak widać mimo iż indeksują tablicę od jedynki to
dość oszczędnie gospodarują pamięcią jednak pełno jest instrukcji break co wskazywałoby na to że kiepsko u nich z logiką skoro muszą wyskakiwać z pętli
Ja starałem się tak napisać aby widać było co z czego wynika jednak nie znalazłem nic o przesunięciu a co do deflacji to też nie wiem jak ją zrealizować

0

Tutaj o przesunięciu i deflacji na postaci Hessenberga produkują się z w miarę obrazowymi schematami:

Thomas Mach Raf Vandebril, "On Deflations in Extended QR Algorithms" Report TW 634, September 2013 (KU Leuven Department of Computer Science Celestijnenlaan 200A – B-3001 Heverlee (Belgium)) TW634.pdf

A tutaj slajdy od tych autorów https://fdocuments.net/document/on-deations-in-extended-qr-algorithms.html?page=3

0

Tutaj produkują się o zabawie w przesunięcia również, przy okazji postai Hessenberga

Blocked Algorithms for the Reduction to
Hessenberg-Triangular Form Revisited
B. K ̊agstr ̈om†, D. Kressner , E.S. Quintana-Ort and G. Quintana-Ort‡
Seminar f ̈ur Angewandte Mathematik
Eidgen ̈ossische Technische Hochschule
CH-8092 Z ̈urich
Switzerland
Research Report No. 2008-17 May 2008
https://www.researchgate.net/publication/225218295_Blocked_algorithms_for_the_reduction_to_Hessenberg-triangular_form_revisited

1 użytkowników online, w tym zalogowanych: 0, gości: 1