src/simulators/tensor_network/matrix_product_state.cpp
//-------------------------------------------------------------------------
// MPS::apply_2_qubit_gate - outline of the algorithm
// 1. Swap qubits A and B until they are consecutive
// 2. Contract MPS_Tensor[A] and MPS_Tensor[B], yielding a temporary four-matrix MPS_Tensor 
//    that represents the entangled states of A and B.
// 3. Apply the gate
// 4. Decompose the temporary MPS_Tensor (using SVD) into U*S*V, where U and V are matrices
//    and S is a diagonal matrix
// 5. U is split by rows to yield two MPS_Tensors representing qubit A (in reshape_U_after_SVD), 
//    V is split by columns to yield two MPS_Tensors representing qubit B (in reshape_V_after_SVD),
//    the diagonal of S becomes the Lambda-vector in between A and B.
//-------------------------------------------------------------------------
:apply_2_qubit_gate - outline of the algorithm
1. Swap qubits A and B until they are consecutive
2. Contract MPS_Tensor[A] and MPS_Tensor[B], yielding a temporary four-matrix MPS_Tensor
that represents the entangled states of A and B.
3. Apply the gate
4. Decompose the temporary MPS_Tensor (using SVD) into U*S*V, where U and V are matrices
and S is a diagonal matrix
5. U is split by rows to yield two MPS_Tensors representing qubit A (in reshape_U_after_SVD),
V is split by columns to yield two MPS_Tensors representing qubit B (in reshape_V_after_SVD),
the diagonal of S becomes the Lambda-vector in between A and B.
: apply_2_qubit_gate - outline of the algorithm 1 . Swap qubits A and B until they are consecutive 2 . Contract MPS_Tensor [ A ] and MPS_Tensor [ B ] yielding a temporary four - matrix MPS_Tensor that represents the entangled states of A and B . 3 . Apply the gate 4 . Decompose the temporary MPS_Tensor ( using SVD ) into U * S * V where U and V are matrices and S is a diagonal matrix 5 . U is split by rows to yield two MPS_Tensors representing qubit A ( in reshape_U_after_SVD ) V is split by columns to yield two MPS_Tensors representing qubit B ( in reshape_V_after_SVD ) the diagonal of S becomes the Lambda - vector in between A and B .
void MPS::apply_2_qubit_gate(uint_t index_A, uint_t index_B, Gates gate_type, cmatrix_t mat)
{
	if(index_A + 1 < index_B)
	{
		apply_swap(index_A,index_B-1);
		apply_2_qubit_gate(index_B-1,index_B, gate_type, mat);
		apply_swap(index_A,index_B-1);
	  return;
	}
	else if(index_A > index_B + 1)
	{
		apply_swap(index_A-1,index_B);
		apply_2_qubit_gate(index_A,index_A-1, gate_type, mat);
		apply_swap(index_A-1,index_B);
		return;
	}
	bool swapped = false;
	if(index_A >  index_B)
	{
	  std::swap(index_A, index_B);
	  swapped = true;
	}
	MPS_Tensor A = q_reg_[index_A], B = q_reg_[index_B];
	rvector_t left_lambda, right_lambda;
	left_lambda  = (index_A != 0) 	    ? lambda_reg_[index_A-1] : rvector_t {1.0};
	right_lambda = (index_B != num_qubits_-1) ? lambda_reg_[index_B  ] : rvector_t {1.0};
	q_reg_[index_A].mul_Gamma_by_left_Lambda(left_lambda);
	q_reg_[index_B].mul_Gamma_by_right_Lambda(right_lambda);
	MPS_Tensor temp = MPS_Tensor::contract(q_reg_[index_A], lambda_reg_[index_A], q_reg_[index_B]);
	switch (gate_type) {
	case cx:
	  temp.apply_cnot(swapped);
	  break;
	case cz:
	  temp.apply_cz();
	  break;
	case id:
	  break;
	case cu1:
	{
	  cmatrix_t Zeros = AER::Utils::Matrix::I-AER::Utils::Matrix::I;
	  cmatrix_t temp1 = AER::Utils::concatenate(AER::Utils::Matrix::I, Zeros , 1),
		    temp2 = AER::Utils::concatenate(Zeros, mat, 1);
	  cmatrix_t cu = AER::Utils::concatenate(temp1, temp2 ,0) ;
	  temp.apply_matrix(cu);
	  break;
	}
	case su4:
	  temp.apply_matrix(mat);
	  break;
	default:
	  throw std::invalid_argument("illegal gate for apply_2_qubit_gate"); 
	}
	MPS_Tensor left_gamma,right_gamma;
	rvector_t lambda;
	MPS_Tensor::Decompose(temp, left_gamma, lambda, right_gamma);
	left_gamma.div_Gamma_by_left_Lambda(left_lambda);
	right_gamma.div_Gamma_by_right_Lambda(right_lambda);
	q_reg_[index_A] = left_gamma;
	lambda_reg_[index_A] = lambda;
	q_reg_[index_B] = right_gamma;
}
void MPS :: apply_2_qubit_gate ( uint_t index_A , uint_t index_B , Gates gate_type , cmatrix_t mat ) { if ( index_A + 1 < index_B ) { apply_swap ( index_A , index_B - 1 ) ; apply_2_qubit_gate ( index_B - 1 , index_B , gate_type , mat ) ; apply_swap ( index_A , index_B - 1 ) ; return ; } else if ( index_A > index_B + 1 ) { apply_swap ( index_A - 1 , index_B ) ; apply_2_qubit_gate ( index_A , index_A - 1 , gate_type , mat ) ; apply_swap ( index_A - 1 , index_B ) ; return ; } bool swapped = false ; if ( index_A > index_B ) { std :: swap ( index_A , index_B ) ; swapped = true ; } MPS_Tensor A = q_reg_ [ index_A ] , B = q_reg_ [ index_B ] ; rvector_t left_lambda , right_lambda ; left_lambda = ( index_A != 0 ) ? lambda_reg_ [ index_A - 1 ] : rvector_t { 1.0 } ; right_lambda = ( index_B != num_qubits_ - 1 ) ? lambda_reg_ [ index_B ] : rvector_t { 1.0 } ; q_reg_ [ index_A ] . mul_Gamma_by_left_Lambda ( left_lambda ) ; q_reg_ [ index_B ] . mul_Gamma_by_right_Lambda ( right_lambda ) ; MPS_Tensor temp = MPS_Tensor :: contract ( q_reg_ [ index_A ] , lambda_reg_ [ index_A ] , q_reg_ [ index_B ] ) ; switch ( gate_type ) { case cx : temp . apply_cnot ( swapped ) ; break ; case cz : temp . apply_cz ( ) ; break ; case id : break ; case cu1 : { cmatrix_t Zeros = AER :: Utils :: Matrix :: I - AER :: Utils :: Matrix :: I ; cmatrix_t temp1 = AER :: Utils :: concatenate ( AER :: Utils :: Matrix :: I , Zeros , 1 ) , temp2 = AER :: Utils :: concatenate ( Zeros , mat , 1 ) ; cmatrix_t cu = AER :: Utils :: concatenate ( temp1 , temp2 , 0 ) ; temp . apply_matrix ( cu ) ; break ; } case su4 : temp . apply_matrix ( mat ) ; break ; default : throw std :: invalid_argument ( " " ) ; } MPS_Tensor left_gamma , right_gamma ; rvector_t lambda ; MPS_Tensor :: Decompose ( temp , left_gamma , lambda , right_gamma ) ; left_gamma . div_Gamma_by_left_Lambda ( left_lambda ) ; right_gamma . div_Gamma_by_right_Lambda ( right_lambda ) ; q_reg_ [ index_A ] = left_gamma ; lambda_reg_ [ index_A ] = lambda ; q_reg_ [ index_B ] = right_gamma ; }
MPS::apply_2_qubit_gate - outline of the algorithm
1.
MPS :: apply_2_qubit_gate - outline of the algorithm 1 .
//for MPS //There is no lambda in the edges of the MPS