Sequential Quantum Gate Decomposer  v1.9.3
Powerful decomposition of general unitarias into one- and two-qubit gates gates
example_SABRE.py
Go to the documentation of this file.
1 from squander import SABRE
2 from squander import Qiskit_IO
3 from squander import utils
4 
5 from qiskit import transpile
6 from qiskit import QuantumCircuit
7 from qiskit.circuit import CircuitInstruction
8 from qiskit.circuit.library import PermutationGate
9 from qiskit_aer import AerSimulator
10 from qiskit.quantum_info import Operator
11 from qiskit import QuantumRegister, ClassicalRegister
12 import numpy as np
13 parameters = np.array([])
14 
15 # The example shows how to transpile a gicen circuit to a new circuit accounting for
16 # the possible connections (i.e. topology or coupling map) between the qubits
17 # The circuit is transformed by SWAP gate insertions and qubit remapping (i.e. reordering)
18 
19 # path to the circuit to be transpiled
20 filename = 'benchmarks/qfast/5q/vqe.qasm'
21 N = 5
22 # load the qasm file into a QISKIT circuit
23 circuit_qiskit = QuantumCircuit.from_qasm_file(filename)
24 
25 # convert the QISKIT circuit into Squander circuti representation
26 Squander_initial_circuit, parameters_initial = Qiskit_IO.convert_Qiskit_to_Squander(circuit_qiskit)
27 
28 # defining the qubit topology/connectivity for Squander
29 topology = [(0,1),(0,2),(0,3),(0,4)]
30 
31 # transpile the circuit by the Sabre method implemented in Squander
32 sabre = SABRE(Squander_initial_circuit, topology)
33 Squander_remapped_circuit, parameters_remapped_circuit, pi, final_pi, swap_count = sabre.map_circuit(parameters_initial)
34 
35 #Umtx = Operator(circuit_qiskit).to_matrix()
36 
37 print("INITIAL CIRCUIT:")
38 print( circuit_qiskit )
39 print("mapping (q -> Q):", pi)
40 print("Final mapping:", final_pi)
41 qubits = list(range(N))
42 Qiskit_circuit = QuantumCircuit(N)
43 pi_map = list(np.array(sabre.get_inverse_pi(pi)))
44 Qiskit_circuit.append(CircuitInstruction( PermutationGate(pi_map),qubits))
45 Qiskit_circuit &= Qiskit_IO.get_Qiskit_Circuit( Squander_remapped_circuit, parameters_remapped_circuit )
46 Qiskit_circuit.append(CircuitInstruction( PermutationGate(list(final_pi)),qubits))
47 print("CIRCUIT MAPPED WITH SABRE:")
48 print( Qiskit_circuit )
49 print("SABRE SWAP COUNT:", swap_count)
50 # defining the qubit topology/connectivity for Squander
51 coupling_map = [[0,1],[0,2],[0,3],[0,4]]
52 '''
53 # transpile the circuit by Qiskit
54 Qiskit_circuit_mapped = transpile(circuit_qiskit, basis_gates=['cx','h','cz','swap','u3'], coupling_map=coupling_map)
55 
56 print("CIRCUIT MAPPED WITH QISKIT:")
57 print( Qiskit_circuit_mapped )
58 print("QISKIT SWAP COUNT:", dict(Qiskit_circuit_mapped.count_ops())['swap'])
59 '''
60 
61 # test the generated squander circuits
62 matrix_size = 1 << Squander_initial_circuit.get_Qbit_Num()
63 unitary_squander_initial = utils.get_unitary_from_qiskit_circuit_operator(circuit_qiskit)
64 
65 #unitary_squander_remapped_circuit = np.eye( 1 << Squander_initial_circuit.get_Qbit_Num(), dtype=np.complex128 )
66 #Squander_remapped_circuit.apply_to( parameters_remapped_circuit, unitary_squander_remapped_circuit)
67 unitary_squander_remapped_circuit = utils.get_unitary_from_qiskit_circuit_operator(Qiskit_circuit)
68 
69 
70 product_matrix = np.dot(unitary_squander_initial.conj().T, unitary_squander_remapped_circuit)
71 phase = np.angle(product_matrix[0,0])
72 product_matrix = product_matrix*np.exp(-1j*phase)
73 
74 
75 product_matrix = np.eye(matrix_size)*2 - product_matrix - product_matrix.conj().T
76 
77 # the error of the decomposition
78 decomposition_error = (np.real(np.trace(product_matrix)))/2
79 
80 print('The error of the decomposition is ' + str(decomposition_error))
81