-
Notifications
You must be signed in to change notification settings - Fork 0
/
quantum_circuit_reduction.py
135 lines (105 loc) · 5.54 KB
/
quantum_circuit_reduction.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
'''
(C) Renata Wong
This code reduces the number of gates in a quantum circuit according to the following rules:
XX = YY = ZZ = HH = I, Sdg x S = S x Sdg = I, CX x CX = II, HZH = X, HXH = Z, SS = Sdg x Sdg = Z
'''
from qiskit import transpile
from qiskit import QuantumCircuit
from qiskit.converters import circuit_to_dag
from qiskit.transpiler import TransformationPass
from qiskit.dagcircuit import DAGOpNode
from qiskit.circuit import Instruction
class GateReduction(TransformationPass):
"""
A transpiler pass to reduce gate number in a circuit.
"""
def run(self, dag):
# take care of cx gates first
# cx gates may be incorrectly removed when processing nodes according to wires
# this happens in multi-wire circuits when there are operators between 2 cx gates on one wire
# but not on another wire
nodes = dag.op_nodes()
for index, node in enumerate(nodes):
if index+1 < len(nodes):
if node.op.name == 'cx':
next_node = nodes[index+1]
if next_node.op.name == node.op.name:
if node.qargs == next_node.qargs:
dag.remove_op_node(node)
dag.remove_op_node(next_node)
nodes.remove(node)
nodes.remove(next_node)
# iterate over all operations, wire after wire
for wire in dag.wires:
# convert iterator nodes_on_wire to a list of nodes
nodes = list(dag.nodes_on_wire(wire, only_ops = True))
for index, node in enumerate(nodes):
if node.op.name in ['x', 'y', 'z', 'h']:
# warning: dag.node_counter produces incorrect values for our use
if index+1 < len(nodes):
next_node = nodes[index+1]
if next_node.op.name == node.op.name:
if node.qargs == next_node.qargs:
dag.remove_op_node(node)
dag.remove_op_node(next_node)
nodes.remove(node)
nodes.remove(next_node)
if index+2 < len(nodes):
if node.op.name == 'h' and next_node.op.name == 'z':
third_node = nodes[index+2]
if third_node.op.name == 'h':
replacement = QuantumCircuit(1)
replacement.x(0)
dag.substitute_node_with_dag(third_node, circuit_to_dag(replacement))
dag.remove_op_node(node)
dag.remove_op_node(next_node)
nodes[index+2] = DAGOpNode(op=Instruction(name='x', num_qubits=1, num_clbits=0, params=[]))
nodes.remove(node)
nodes.remove(next_node)
if index+2 < len(nodes):
if node.op.name == 'h' and next_node.op.name == 'x':
third_node = nodes[index+2]
if third_node.op.name == 'h':
replacement = QuantumCircuit(1)
replacement.z(0)
dag.substitute_node_with_dag(third_node, circuit_to_dag(replacement))
dag.remove_op_node(node)
dag.remove_op_node(next_node)
nodes[index+2] = DAGOpNode(op=Instruction(name='z', num_qubits=1, num_clbits=0, params=[]))
nodes.remove(node)
nodes.remove(next_node)
if node.op.name in ['s', 'sdg']:
if index+1 < len(nodes):
next_node = nodes[index+1]
if next_node.op.name in ['s', 'sdg']:
if next_node.op.name != node.op.name:
dag.remove_op_node(node)
dag.remove_op_node(next_node)
nodes.remove(node)
nodes.remove(next_node)
elif next_node.op.name == node.op.name:
dag.remove_op_node(node)
nodes.remove(node)
replacement = QuantumCircuit(1)
replacement.z(0)
dag.substitute_node_with_dag(next_node, circuit_to_dag(replacement))
nodes[index+1] = DAGOpNode(op=Instruction(name='z', num_qubits=1, num_clbits=0, params=[]))
return dag
def reduce_circuit_depth(circuit: QuantumCircuit):
"""
Iterative method for circuit reduction.
circuit:
a QuantumCircuit object that is to be reduced
Returns:
reduced_circuit:
the reduced circuit
"""
circuit_size = circuit.size()
reduced_circuit = circuit.copy()
while True:
reduced_circuit = GateReduction()(reduced_circuit)
if circuit_size == reduced_circuit.size():
break
else:
circuit_size = reduced_circuit.size()
return reduced_circuit