Sequential Quantum Gate Decomposer  v1.9.6
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 = 'examples/partitioning/qasm_samples/heisenberg-16-20.qasm'
21 N = 16
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), (0, 5), (0, 6), (0, 7),
30  (8, 9), (8, 10), (8, 11), (8, 12), (8, 13), (8, 14), (8, 15),
31  (0, 8),]
32 
33 # transpile the circuit by the Sabre method implemented in Squander
34 sabre = SABRE(Squander_initial_circuit, topology,stochastic_selection=True)
35 Squander_remapped_circuit, parameters_remapped_circuit, pi, final_pi, swap_count = sabre.map_circuit(parameters_initial,30)
36 
37 #Umtx = Operator(circuit_qiskit).to_matrix()
38 
39 print("INITIAL CIRCUIT:")
40 #print( circuit_qiskit )
41 print("mapping (q -> Q):", pi)
42 print("Final mapping:", final_pi)
43 qubits = list(range(N))
44 Qiskit_circuit = QuantumCircuit(N)
45 pi_map = list(np.array(sabre.get_inverse_pi(pi)))
46 Qiskit_circuit.append(CircuitInstruction( PermutationGate(pi_map),qubits))
47 Qiskit_circuit &= Qiskit_IO.get_Qiskit_Circuit( Squander_remapped_circuit, parameters_remapped_circuit )
48 Qiskit_circuit.append(CircuitInstruction( PermutationGate(list(final_pi)),qubits))
49 print("CIRCUIT MAPPED WITH SABRE:")
50 #print( Qiskit_circuit )
51 print("SABRE SWAP COUNT:", swap_count)
52 # defining the qubit topology/connectivity for Squander
53 coupling_map = [
54  [0, 1], [0, 2], [0, 3], [0, 4], [0, 5], [0, 6], [0, 7],
55  [8, 9], [8, 10], [8, 11], [8, 12], [8, 13], [8, 14], [8, 15],
56  [0, 8],
57 ]
58 # transpile the circuit by Qiskit
59 Qiskit_circuit_mapped = transpile(circuit_qiskit, coupling_map=coupling_map)
60 
61 print("CIRCUIT MAPPED WITH QISKIT:")
62 #print( Qiskit_circuit_mapped )
63 print("QISKIT SWAP COUNT:", dict(Qiskit_circuit_mapped.count_ops())['swap'])
64 
65 # test the generated squander circuits
66 #matrix_size = 1 << Squander_initial_circuit.get_Qbit_Num()
67 #unitary_squander_initial = utils.get_unitary_from_qiskit_circuit_operator(circuit_qiskit)
68 
69 #unitary_squander_remapped_circuit = np.eye( 1 << Squander_initial_circuit.get_Qbit_Num(), dtype=np.complex128 )
70 #Squander_remapped_circuit.apply_to( parameters_remapped_circuit, unitary_squander_remapped_circuit)
71 """
72 unitary_squander_remapped_circuit = utils.get_unitary_from_qiskit_circuit_operator(Qiskit_circuit)
73 
74 
75 product_matrix = np.dot(unitary_squander_initial.conj().T, unitary_squander_remapped_circuit)
76 phase = np.angle(product_matrix[0,0])
77 product_matrix = product_matrix*np.exp(-1j*phase)
78 
79 
80 product_matrix = np.eye(matrix_size)*2 - product_matrix - product_matrix.conj().T
81 
82 # the error of the decomposition
83 decomposition_error = (np.real(np.trace(product_matrix)))/2
84 
85 print('The error of the decomposition is ' + str(decomposition_error))
86 
87 """