User Tools

Site Tools


Action disabled: revisions
de:implementation

Implementation

DMRG

In diesem Abschnitt werden die einzelnen Klassen beschrieben, die zu dieser Implementation der DMRG gehören. Obwohl es sich bei dem Applet jederzeit um eine Spin-\(\frac{1}{2}\)-Kette handelt, sind alle Klassen mit einer variablen Anzahl an möglichen lokalen Zuständen implementiert.

Matrix

Anordnung der Matrixelemente ((Author: HB, Lizenz: Creative Common by-sa, Quelle: http://commons.wikimedia.org/wiki/File:Matrice.svg?uselang=de))

Die Klasse “Matrix” implementiert über einen reinen Speicher von zwei-dimensional angeordneten Werten hinaus auch Wrapper für folgende jlapack-Funktionen 1)2):

  • DGEMM - Matrixmultiplikation (mult), Matrixaddition (add), Matrixsubtraktion (sub) und Transponieren (trans)
  • DGESVD - Single value decomposition (svd)
  • DSYEV - Exakte Diagonalisierung (Eigen)

Darüber hinaus ist es möglich, zwei Matrizen horizontal oder vertikal aneinander zu heften (merge). Die nötigen Daten um sie wieder zu trennen (split), werden innerhalb der Klasse gespeichert, wobei zu beachten ist, dass immer die letzte Heftung aufgetrennt wird.

MatrixMatrix

Diese Klasse bietet die Möglichkeit, dass eine Matrix Matrizen enthält, wie es durch die hier eingeführten \(\hat W^{\left[i\right]}\) notwendig ist. Da auf einer solchen Matrix Operationen wie die SVD oder die exakte Diagonalisierung nicht sinnvoll wären, sind diese auch nicht implementiert.

Mps

In dieser Klasse sind drei zwei-dimensionale Matrix-Arrays enthalten. Eines enthält die M-, A- bzw. B-Matrizen. Die anderen beiden enthalten die R- und L-Matrizen. Zum Erstellen eines Mps stehen zwei Konstruktoren zur Verfügung. Einer füllt die M-Matrizen zufällig. Der andere Konstruktor erzeugt einen vorgegebenen Zustand. Dieser muss als ein-dimensionales Array, welches die Koeffizienten enthält, vorgegeben werden. Beide Konstruktoren links-normalisieren anschließend den MPS. Bei diesem Vorgang werden auch die R-Matrizen gefüllt, weshalb es notwendig ist einen zugehörigen MPO anzugeben.

public void BuildR(Mpo H, int N)
{
	Matrix Eins = new Matrix(1,1); Eins.SetContent(0,0,1);
	for (int a=0; a<this.A[N+1][0].GetSize()[0];a++)
	{
		this.R[N][a] = new Matrix(H.W[N+1][0][0].GetSize()[0], this.A[N+1][0].GetSize()[0]);
		for (int j=0; j<this.states; j++)
			for (int k=0; k<this.states; k++)
				for (int l=0; l<this.A[N+1][0].GetSize()[1]; l++)
					if (N>this.N-2)
						for (int m=0; m<this.A[N+1][j].GetSize()[0]; m++)
							for (int o=0; o<H.W[N+1][j][k].GetSize()[0]; o++)
								this.R[N][a].SetContent(o,m, this.R[N][a].GetContent(o,m)+this.A[N+1][j].GetContent(0,m)*H.W[N+1][j][k].GetContent(0,o)*this.A[N+1][k].GetContent(0,a));
					else
						this.R[N][a] = new Matrix(this.R[N][a].add(H.W[N+1][j][k].mult(this.R[N+1][l].trans()).mult(this.A[N+1][k].trans()).mult(this.A[N+1][j].GetContent(l,a)).trans()));
	}
}

Das Übergeben des MPO ist ebenfalls notwendig, wenn ein “Sweep-Step” gemacht wird, da auch hier die L- und R-Matrizen neu gefüllt werden.

public Matrix DoLeftSweepStep(int j, Mpo op)
{
	Matrix AAllStates = new Matrix(this.A[j][0]);
	for (int k=1; k<this.states; k++)
		AAllStates.merge(this.A[j][k], false);
 
	Matrix u=new Matrix();
	Matrix vt=new Matrix();
	Matrix s=AAllStates.svd(u, vt);
 
	for (int i=vt.Merges.length;i>=0;i--)
		this.A[j][i]=vt.split();
	for (int i=0; i<this.states; i++)
		this.A[j-1][i]=(this.A[j-1][i].mult(u).mult(s));
	this.BuildR(op, j-1);
	return s;
}

Auch das hier beschriebene Skalarprodukt ist in dieser Klasse implementiert:

public double ScalarProd(Mps b)
{
	if (this.N != b.N)
		return 0.0;
	Matrix out = new Matrix();
	Matrix pre_out = new Matrix();
	pre_out = this.A[0][0].trans().mult(b.A[0][0]);
	for (int s=1; s<this.states;s++)
		pre_out = pre_out.add(this.A[0][s].trans().mult(b.A[0][s]));
	out = new Matrix(pre_out);
	for (int i=1;i<this.N;i++)
	{
		pre_out = this.A[i][0].trans().mult(out).mult(b.A[i][0]);
		for ( int s=1; s<this.states;s++)
			pre_out = pre_out.add(this.A[i][s].trans().mult(out).mult(b.A[i][s]));
		out = new Matrix(pre_out);
	}
	return out.GetContent(0,0);
}

Mpo

Um die MPO-Matrizen zu speichern, verwendet die Klasse Mpo ein drei-dimensionales Matrizen-Array. Beim Erzeugen einer Instanz dieser Klasse gibt es die Möglichkeit, ein “MatrixMatrix”-Array mit alles $\hat W^{\left[i\right]}$ zu übergeben. Alternativ kann auch nur eine einzelne “MatrixMatrix” übergeben werden, hierbei wird $\hat W^{\left[1\right]}$ aus der letzten Zeile und $\hat W^{\left[L\right]}$ aus der ersten Spalte erzeugt. Die Anwendung eines Mpo-Objektes auf ein Mps-Objekt ist, wie hier beschrieben, durch die Funktion mult implementiert:

public Mps mult(Mps b)
{
	Mps out = new Mps(this.N, b.d*this.W[0][0][0].GetSize()[1], b.d_max*this.W[this.N/2][0][0].GetSize()[1], this.states);
	for (int l=0; l<this.N; l++)
		for (int i=0; i<this.states; i++)
			for (int j=0; j<this.states; j++)
				for (int m=0; m<b.A[l][i].GetSize()[0];m++)
					for (int o=0; o<b.A[l][i].GetSize()[1];o++)
						for (int q=0; q<this.W[l][i][j].GetSize()[0];q++)
							for (int r=0; r<this.W[l][i][j].GetSize()[1];r++)
								out.A[l][i].SetContent(r*b.A[l][i].GetSize()[1]+o, q*b.A[l][i].GetSize()[0]+m, out.A[l][i].GetContent(r*b.A[l][i].GetSize()[1]+o, q*b.A[l][i].GetSize()[0]+m)+this.W[l][i][j].GetContent(r, q)*b.A[l][j].GetContent(o, m));
	return out;
}

Dmrg

Die Klasse “Dmrg” beinhaltet ein Mps-Objekt und ein Mpo-Objekt und stellt sowohl den Algorithmus, als auch die Schnittstelle zur GUI dar. Die Kernaufgaben übernehmen hierbei vier Funktionen, die im Folgenden dargestellt werden.

  • DoNextStep

Diese Funktion ist die einzige, neben dem Konstruktor, die von außen aufgerufen wird. Sie kümmert sich darum, dass immer in die richtige Richtung gesweept wird.

  • DoRightStep

Hier wird ein kompletter Sweep-Step nach rechts vorgenommen. Dazu muss zunächst der effektive Hamiltonien $H_{\text{Eff}}$ erstellt werden (Zeile 125). Dieser muss dann diagonalisiert werden (Zeile 126). Anschließend wird der Eigenvektor in die MPS-Matrix des bearbeiteten Platzes eingeordnet (Zeilen 128 bis 135). Mit dem rechts-Normalisieren in Zeile 137 ist der eigentliche Sweep-Step abgeschlossen. Zuletzt werden dann noch die Ergebnisse der verschiedenen Operationen gespeichert (Zeile 138 bis 142), damit sie später ausgelesen werden können.

public void DoRightStep(int N)
{
	Matrix H = this.BuildHeff(N);
	double[] EigenValue = H.Eigen();
	Matrix[] M = new Matrix[this.state.states];
	for (int i=0; i<this.state.states; i++)
	{
		M[i] = new Matrix(this.state.A[N][0].GetSize()[1], this.state.A[N][0].GetSize()[0]);
		for (int m=0; m<this.state.A[N][0].GetSize()[0]; m++)
			for (int o=0; o<this.state.A[N][0].GetSize()[1]; o++)
				M[i].SetContent(o, m, H.GetContent(0, (i*this.state.A[N][0].GetSize()[0]*this.state.A[N][0].GetSize()[1])+(m*this.state.A[N][0].GetSize()[1])+o));
		this.state.A[N][i] = new Matrix(M[i]);
	}
	this.CalcSxSz();
	Matrix s = this.state.DoRightSweepStep(N, this.operator);
	s = s.mult(s);
	this.CurrentDm = new double[s.GetSize()[0]];
	for (int i = 0; i<this.CurrentDm.length; i++)
		this.CurrentDm[i] = s.GetContent(i,i);
	this.CurrentEnergy = EigenValue[0];
}
  • DoLeftStep

Diese Funktion entspricht der Funktion DoRightStep mit der Ausnahme, dass links-normalisiert wird.

  • BuildHeff

Um $H_{\text{Eff}}$ zu bilden, wird zunächst ein Zwischenspeicher $LWR^{[\sigma][\sigma^\prime][a_l][a_{l-1}]}$ erstellt. Hierzu kann man mehrere Summen in Matrixprodukte umformulieren, wie hier gezeigt. Anschließend werden dann alle Werte einzeln in $H_{\text{Eff}}$ einsortiert.

public Matrix BuildHeff(int N)
{
	int Size = this.state.states*this.state.A[N][0].GetSize()[0]*this.state.A[N][0].GetSize()[1];
	Matrix H = new Matrix(Size, Size);
	Matrix[][][][] LWR = new Matrix[this.state.states][this.state.states][this.state.A[N][0].GetSize()[0]][this.state.A[N][0].GetSize()[1]];
	for (int i=0; i<this.state.states; i++)
		for (int j=0; j<this.state.states; j++)
			for (int m=0; m<this.state.A[N][0].GetSize()[0]; m++)
				for (int o=0; o<this.state.A[N][0].GetSize()[1]; o++)
					if (N-1 < 0)
						LWR[i][j][m][o] = new Matrix((this.operator.W[N][i][j].mult(this.state.R[N][o].trans())));
					else
						LWR[i][j][m][o] = new Matrix(this.state.L[N-1][m].mult(this.operator.W[N][i][j].mult(this.state.R[N][o].trans())));
 
	for (int i=0; i<this.state.states; i++)
		for (int j=0; j<this.state.states; j++)
			for (int m=0; m<this.state.A[N][0].GetSize()[0]; m++)
				for (int n=0; n<this.state.A[N][0].GetSize()[0]; n++)
					for (int o=0; o<this.state.A[N][0].GetSize()[1]; o++)
						for (int p=0; p<this.state.A[N][0].GetSize()[1]; p++)
							H.SetContent((j*this.state.A[N][0].GetSize()[0]*this.state.A[N][0].GetSize()[1])+(n*this.state.A[N][0].GetSize()[1])+p, (i*this.state.A[N][0].GetSize()[0]*this.state.A[N][0].GetSize()[1])+(m*this.state.A[N][0].GetSize()[1])+o, LWR[i][j][m][o].GetContent(p,n));
	return H;
}

Applet

In diesem Abschnitt werden die Klassen und Bibliotheken beschrieben, die zum Erstellen der GUI notwendig sind.

DmrgCollector

Diese Klasse, die von der jchart2D-Klasse “ADataCollector” abgeleitet ist, fügt den einzelnen Charts Datenpunkte hinzu. Damit dies, inklusive der Berechnungen, parallel zur Bedienung des Applets möglich ist, implementiert diese Klasse das Interface “Runnable” 3), wodurch diese Klasse in einem eigenen Thread ausgeführt wird. Die gesamten Berechnungen werden aus der Funktion “collectData” heraus gestartet bzw. in dieser durchgeführt. Zunächst wird überprüft, ob das Sweep-Limit erreicht wurde:

// Maximale Anzahl an Sweeps erreicht? ==> Stop
if (this.visuRef.DmrgRef.CurrentSweep == this.visuRef.Sweeps)
	this.visuRef.stopData();

Anschließend wir der eigentliche Sweep ausgeführt und der neu berechnete Energiepunkt direkt in den Energie-Chart eingefügt:

// Erzeuge neue Daten
int y = this.visuRef.DmrgRef.DoNextStep();

Im Folgenden wird die Spur der Dichtematrix aktualisiert:

// Aktualisiere die Spur der Dichtematrix
this.visuRef.getDmTrace().removeAllPoints();
for (int i = 0; i<this.visuRef.DmrgRef.CurrentDm.length; i++)
	this.visuRef.getDmTrace().addPoint(i, this.visuRef.DmrgRef.CurrentDm[i]);

Danach werden die Erwartungswerte bestimmt. Hierzu wird eine Operator-Klasse verwendet, die lediglich Single-Site-Operatoren unterstützt.

// Aktualisieren der Erwartungswerte für Sx und Sz
for (int i=0; i<this.visuRef.Site; i++)
{
	this.visuRef.getErwSzTrace().addPoint(i, this.visuRef.DmrgRef.CurrentSzExV[i]);
	this.visuRef.getErwSxTrace().addPoint(i, this.visuRef.DmrgRef.CurrentSxExV[i]);
}		

Anschließend wird die Entanglement-Entropie berechnet.

// Bestimme die entanglement entropy
double enen = 0.0;
for (int i = 0; i<this.visuRef.DmrgRef.CurrentDm.length; i++)
	enen = enen + this.visuRef.DmrgRef.CurrentDm[i]*(Math.log(this.visuRef.DmrgRef.CurrentDm[i])/Math.log(2.0));
this.visuRef.getEeTrace().addPoint(y+0.5*(this.visuRef.DmrgRef.Direction==false?1:-1),-enen);

Der Rest der Funktion erledigt die Textausgabe und die Positionierung des Positionsbalkens.

visu

Die Klasse visu beinhaltet die main-Funktion und die gesamte grafische Oberfläche. Das bedeutet, dass alle Objekte instanziiert werden, die später die Ausgabe übernehmen. Darüber hinaus werden in dieser Klasse alle Matrizen und Operatoren definiert und gespeichert. Dies wiederum führt dazu, dass sämtliche Einstellmöglichkeiten in dieser Klasse zu finden sind.

Graphen werden mit Hilfe der Bibliothek JChart2D angezeigt 4).

©: This site was created by Thomas Köhler

1)
Anderson, E. ; Bai, Z. ; Bischof, C. ; Blackford, S. ; Demmel, J. ; Dongarra, J. ; Du Croz, J. ; Greenbaum, A. ; Hammarling, S. ; McKenney, A. ; Sorensen, D.: LAPACK Users’ Guide. Third. Philadelphia, PA : Society for Industrial and Applied Mathematics, 1999. – ISBN 0-89871-447-8 (paperback)
2)
Doolin, David M. ; Dongarra, Jack ; Seymour, Keith: JLAPACK - compiling LAPACK Fortran to Java. In: Sci. Program. 7 (1999), April, S. 111–138. – URL http://portal.acm.org/citation.cfm?id=1239860.1239868. – ISSN 1058-9244
de/implementation.txt · Last modified: 2019/06/04 21:43 by thomas