package dmrgvisu2;

public class Mpo
{
	private static final long serialVersionUID = 1L;
	int N;
	Matrix[][][] W;
	int d;
	int d_max;
	int states;

	public Mpo()
	{
		System.out.println("DNU! MPO-Constructor");
		this.d=1;
		this.N=4;
		this.states=2;
		this.W = new Matrix[this.N][this.states][this.states];
		for (int i=0; i<this.N/2; i++)
		{
			for (int j=0; j<this.states; j++)
			{
				for (int k=0; k<this.states; k++)
				{
					this.W[i][j][k]=new Matrix(this.d,this.d);
					this.W[this.N-i-1][j][k]=new Matrix(this.d,this.d);
				}
			}
		}
	}
	
	public Mpo(int N, int states, int d)
	{
		this.d=d;
		this.N=N;
		this.states=states;
		this.W = new Matrix[this.N][this.states][this.states];
		for (int i=0; i<this.N; i++)
		{
			for (int j=0; j<this.states; j++)
			{
				for (int k=0; k<this.states; k++)
				{				
					this.W[i][j][k]=new Matrix(this.d,this.d);
					this.W[i][j][k].SetContent(0,0,1);
				}
			}
		}
	}
	
	public void SetLocal(int N, Matrix Op)
	{
		for(int i=0; i<this.states; i++)
			for(int j=0; j<this.states; j++)
				this.W[N][i][j].SetContent(0, 0, Op.GetContent(i,j));
	}
	public void DelLocal(int N)
	{
		for(int i=0; i<this.states; i++)
			for(int j=0; j<this.states; j++)
				this.W[N][i][j].SetContent(0, 0, i==j?1:0);
	}
	public Mpo(MatrixMatrix H, int N, int states, int d)
	{
		MatrixMatrix[] Ws = new MatrixMatrix[N];
		/* Erzeuge W^[1] */
		Ws[0] = new MatrixMatrix(H.GetSize()[1], 1);
		for (int i=0; i<H.GetSize()[1]; i++)
			Ws[0].SetContent(i, 0, H.GetContent(i,H.GetSize()[1]-1));
		
		/* Erzeuge alle W^[i] mit i!=1,N */
		for (int j=1; j<N-1; j++)
			Ws[j] = new MatrixMatrix(H);
			
		/* Erzeuge W^[N] */
		Ws[N-1] = new MatrixMatrix(1, H.GetSize()[0]);
		for (int i=0; i<H.GetSize()[0]; i++)
			Ws[N-1].SetContent(0, i, H.GetContent(0, i));

		/* Erstelle aus dem generierten W einen MPO */
		this.init(Ws, N, states, d);
	}
	
	private void init(MatrixMatrix[] H, int N, int states, int d)
	{
		this.d=d;				// Groesse der Matrizen					
		this.N=N;				// Laenge der Kette
		this.states=states;		// Anzahl der moeglichen Zustaende (Anzahl der Matrizen pro Kettenplatz)
		this.W = new Matrix[this.N][this.states][this.states];
		for (int k=0; k<this.N; k++)
		{
			for (int i=0; i<this.states; i++)
			{
				for (int j=0; j<this.states; j++)
				{
					this.W[k][i][j] = new Matrix(H[k].GetSize()[1], H[k].GetSize()[0]);
					for (int l=0; l<this.W[k][i][j].GetSize()[1]; l++)
						for (int m=0; m<this.W[k][i][j].GetSize()[0]; m++)
							this.W[k][i][j].SetContent(l, m, H[k].GetContent(l, m).GetContent(i, j));
				}
			}
		}
	}
	
	public Mpo(MatrixMatrix[] H, int N, int states, int d)
	{
		this.init(H, N, states, d);
	}
	
	public String toString()
	{
		String newString = "";
		for (int i=0; i<this.N; i++)
			for (int j=0; j<this.states; j++)
				for (int k=0; k<this.states; k++)
					newString = newString + this.W[i][j][k];
		return newString;
	}

	public void printreadable()
	{
		for (int i=0; i<this.N; i++)
		{
			for (int j=0; j<this.states; j++)
			{
				for (int k=0; k<this.states; k++)
				{
					System.out.println("W[" + i + "][" + j + "][" + k + "]");
					this.W[i][j][k].printreadable();
				}
			}
		}
		return;
	}
	
	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;
	}

}