forked from Qiskit/qiskit
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathtest_blueprintcircuit.py
214 lines (170 loc) · 6.57 KB
/
test_blueprintcircuit.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
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
# This code is part of Qiskit.
#
# (C) Copyright IBM 2017, 2020.
#
# This code is licensed under the Apache License, Version 2.0. You may
# obtain a copy of this license in the LICENSE.txt file in the root directory
# of this source tree or at http://www.apache.org/licenses/LICENSE-2.0.
#
# Any modifications or derivative works of this code must retain this
# copyright notice, and modified files need to carry a notice indicating
# that they have been altered from the originals.
"""Test the blueprint circuit."""
import math
import unittest
from ddt import ddt, data
from qiskit.test.base import QiskitTestCase
from qiskit.circuit import (
QuantumRegister,
Parameter,
QuantumCircuit,
Gate,
Instruction,
CircuitInstruction,
)
from qiskit.circuit.library import BlueprintCircuit, XGate
class MockBlueprint(BlueprintCircuit):
"""A mock blueprint class."""
def __init__(self, num_qubits):
super().__init__(name="mock")
self.num_qubits = num_qubits
@property
def num_qubits(self):
return self._num_qubits
@num_qubits.setter
def num_qubits(self, num_qubits):
self._invalidate()
self._num_qubits = num_qubits
self.qregs = [QuantumRegister(self.num_qubits, name="q")]
def _check_configuration(self, raise_on_failure=True):
valid = True
if self.num_qubits is None:
valid = False
if raise_on_failure:
raise AttributeError("The number of qubits was not set.")
if self.num_qubits < 1:
valid = False
if raise_on_failure:
raise ValueError("The number of qubits must at least be 1.")
return valid
def _build(self):
super()._build()
self.rx(Parameter("angle"), 0)
self.h(self.qubits)
@ddt
class TestBlueprintCircuit(QiskitTestCase):
"""Test the blueprint circuit."""
def test_invalidate_rebuild(self):
"""Test that invalidate and build reset and set _data and _parameter_table."""
mock = MockBlueprint(5)
mock._build()
with self.subTest(msg="after building"):
self.assertGreater(len(mock._data), 0)
self.assertEqual(len(mock._parameter_table), 1)
mock._invalidate()
with self.subTest(msg="after invalidating"):
self.assertFalse(mock._is_built)
self.assertEqual(len(mock._parameter_table), 0)
mock._build()
with self.subTest(msg="after re-building"):
self.assertGreater(len(mock._data), 0)
self.assertEqual(len(mock._parameter_table), 1)
def test_calling_attributes_works(self):
"""Test that the circuit is constructed when attributes are called."""
properties = ["data"]
for prop in properties:
with self.subTest(prop=prop):
circuit = MockBlueprint(3)
getattr(circuit, prop)
self.assertGreater(len(circuit._data), 0)
methods = [
"qasm",
"count_ops",
"num_connected_components",
"num_nonlocal_gates",
"depth",
"__len__",
"copy",
"inverse",
]
for method in methods:
with self.subTest(method=method):
circuit = MockBlueprint(3)
if method == "qasm":
continue # raises since parameterized circuits produce invalid qasm 2.0.
getattr(circuit, method)()
self.assertGreater(len(circuit._data), 0)
with self.subTest(method="__get__[0]"):
circuit = MockBlueprint(3)
_ = circuit[2]
self.assertGreater(len(circuit._data), 0)
def test_compose_works(self):
"""Test that the circuit is constructed when compose is called."""
qc = QuantumCircuit(3)
qc.x([0, 1, 2])
circuit = MockBlueprint(3)
circuit.compose(qc, inplace=True)
reference = QuantumCircuit(3)
reference.rx(list(circuit.parameters)[0], 0)
reference.h([0, 1, 2])
reference.x([0, 1, 2])
self.assertEqual(reference, circuit)
@data("gate", "instruction")
def test_to_gate_and_instruction(self, method):
"""Test calling to_gate and to_instruction works without calling _build first."""
circuit = MockBlueprint(2)
if method == "gate":
gate = circuit.to_gate()
self.assertIsInstance(gate, Gate)
else:
gate = circuit.to_instruction()
self.assertIsInstance(gate, Instruction)
def test_build_before_appends(self):
"""Test that both forms of direct append (public and semi-public) function correctly."""
class DummyBlueprint(BlueprintCircuit):
"""Dummy circuit."""
def _check_configuration(self, raise_on_failure=True):
return True
def _build(self):
super()._build()
self.z(0)
expected = QuantumCircuit(2)
expected.z(0)
expected.x(0)
qr = QuantumRegister(2, "q")
mock = DummyBlueprint()
mock.add_register(qr)
mock.append(XGate(), [qr[0]], [])
self.assertEqual(expected, mock)
mock = DummyBlueprint()
mock.add_register(qr)
mock._append(CircuitInstruction(XGate(), (qr[0],), ()))
self.assertEqual(expected, mock)
def test_global_phase_copied(self):
"""Test that a global-phase parameter is correctly propagated through."""
class DummyBlueprint(BlueprintCircuit):
"""Dummy circuit."""
def _check_configuration(self, raise_on_failure=True):
return True
def _build(self):
# We don't need to do anything, we just need `_build` to be non-abstract.
# pylint: disable=useless-parent-delegation
return super()._build()
base = DummyBlueprint()
base.global_phase = math.pi / 2
self.assertEqual(base.copy_empty_like().global_phase, math.pi / 2)
self.assertEqual(base.copy().global_phase, math.pi / 2)
# Verify that a parametric global phase can be assigned after the copy.
a = Parameter("a")
parametric = DummyBlueprint()
parametric.global_phase = a
self.assertEqual(
parametric.copy_empty_like().assign_parameters({a: math.pi / 2}).global_phase,
math.pi / 2,
)
self.assertEqual(
parametric.copy().assign_parameters({a: math.pi / 2}).global_phase,
math.pi / 2,
)
if __name__ == "__main__":
unittest.main()