Sequential Quantum Gate Decomposer  v1.9.3
Powerful decomposition of general unitarias into one- and two-qubit gates gates
test_QX2.py
Go to the documentation of this file.
1 # -*- coding: utf-8 -*-
2 """
3 Created on Fri Jun 26 14:42:56 2020
4 Copyright 2020 Peter Rakyta, Ph.D.
5 
6 Licensed under the Apache License, Version 2.0 (the "License");
7 you may not use this file except in compliance with the License.
8 You may obtain a copy of the License at
9 
10  http://www.apache.org/licenses/LICENSE-2.0
11 
12 Unless required by applicable law or agreed to in writing, software
13 distributed under the License is distributed on an "AS IS" BASIS,
14 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 See the License for the specific language governing permissions and
16 limitations under the License.
17 
18 You should have received a copy of the GNU General Public License
19 along with this program. If not, see http://www.gnu.org/licenses/.
20 
21 @author: Peter Rakyta, Ph.D.
22 """
23 
25 
26 
27 
28 # cerate unitary q-bit matrix
29 from scipy.stats import unitary_group
30 import numpy as np
31 from squander import utils
32 
33 
34 try:
35  from mpi4py import MPI
36  MPI_imported = True
37 except ModuleNotFoundError:
38  MPI_imported = False
39 
40 
41 
42 
44  """This is a test class of the python iterface to the decompsition classes of the QGD package"""
45 
46 
47 
48 
49 
51  r"""
52  This method is called by pytest.
53  Test to define custom gate structure in the decomposition
54 
55  """
56 
57  from squander import N_Qubit_Decomposition
58 
59  # the number of qubits spanning the unitary
60  qbit_num = 4
61 
62  # determine the soze of the unitary to be decomposed
63  matrix_size = int(2**qbit_num)
64 
65  # creating a random unitary to be decomposed
66  Umtx = unitary_group.rvs(matrix_size)
67 
68  # creating an instance of the C++ class
69  decomp = N_Qubit_Decomposition( Umtx.conj().T )
70 
71  # list of reordered qubits (original: (3,2,1,0) )
72  reordered_qbits = (0,1,3,2)
73 
74  # adding custom gate structure to the decomposition
75  decomp.Reorder_Qubits( reordered_qbits )
76 
77 
78  # create custom gate structure
79  gate_structure = { 4: self.create_custom_gate_structure_QX2(4), 3: self.create_custom_gate_structure_QX2(3)}
80 
81 
82  # adding custom gate structure to the decomposition
83  decomp.set_Gate_Structure( gate_structure )
84 
85 
86  # set the maximal number of layers in the decomposition
87  decomp.set_Max_Layer_Num( {4: 60, 3:16} )
88 
89  # set the number of block to be optimized in one shot
90  decomp.set_Optimization_Blocks( 20 )
91 
92  # starting the decomposition
93  decomp.Start_Decomposition()
94 
95  # list of reordered qubits to revert the initial order
96  revert_qbits = (1,0,2,3)
97 
98  # adding custom gate structure to the decomposition
99  decomp.Reorder_Qubits( revert_qbits )
100 
101  # list the decomposing operations
102  decomp.List_Gates()
103 
104  # get the decomposing operations
105  quantum_circuit = decomp.get_Qiskit_Circuit()
106 
107  import numpy.linalg as LA
108 
109  # test the decomposition of the matrix
110  # the unitary matrix from the result object
111  decomposed_matrix = np.asarray( utils.get_unitary_from_qiskit_circuit( quantum_circuit ) )
112  product_matrix = np.dot(Umtx,decomposed_matrix.conj().T)
113  phase = np.angle(product_matrix[0,0])
114  product_matrix = product_matrix*np.exp(-1j*phase)
115 
116  product_matrix = np.eye(matrix_size)*2 - product_matrix - product_matrix.conj().T
117  # the error of the decomposition
118  decomposition_error = (np.real(np.trace(product_matrix)))/2
119 
120  print('The error of the decomposition is ' + str(decomposition_error))
121 
122  assert( decomposition_error < 1e-3 )
123 
124 
125  def create_custom_gate_structure_QX2(self, qbit_num):
126  r"""
127  This method is called to create custom gate structure for the decomposition on IBM QX2
128 
129  """
130 
131  from squander import Circuit
132 
133  # creating an instance of the wrapper class Circuit
134  Circuit_ret = Circuit( qbit_num )
135 
136  disentangle_qbit = qbit_num - 1
137 
138 
139 
140  for qbit in range(0, disentangle_qbit ):
141 
142  # creating an instance of the wrapper class Circuit
143  Layer = Circuit( qbit_num )
144 
145 
146  if qbit == 0:
147 
148  # add U3 fate to the block
149  Theta = True
150  Phi = False
151  Lambda = True
152  Layer.add_U3( 0 )
153  Layer.add_U3( disentangle_qbit )
154 
155  # add CNOT gate to the block
156  Layer.add_CNOT( 0, disentangle_qbit)
157 
158  elif qbit == 1:
159 
160  # add U3 fate to the block
161  Theta = True
162  Phi = False
163  Lambda = True
164  Layer.add_U3( 0 )
165  Layer.add_U3( 1 )
166 
167  # add CNOT gate to the block
168  Layer.add_CNOT( 0, 1)
169 
170 
171 
172  elif qbit == 2:
173 
174  # add U3 fate to the block
175  Theta = True
176  Phi = False
177  Lambda = True
178  Layer.add_U3( 2 )
179  Layer.add_U3( disentangle_qbit )
180 
181  # add CNOT gate to the block
182  Layer.add_CNOT( 2, disentangle_qbit )
183 
184 
185 
186  Circuit_ret.add_Circuit( Layer )
187 
188  return Circuit_ret
189 
190 
191 
192 
def create_custom_gate_structure_QX2(self, qbit_num)
Definition: test_QX2.py:125
A base class to determine the decomposition of an N-qubit unitary into a sequence of CNOT and U3 gate...