Browse code

Add tests for applying gates to a state

For the moment we only test single-qubit and controlled single-qubit
gates, as these gates can be easily expressed on the full Hilbert
space. A single qubit gate is just a tensor product, and a
controlled single-qubit gate is the sum of 2 tensor products.

The only real room for error when implementing gate application
will be in the ordering of the qubits, and these two tests are
already sensitive enough to catch this. Nevertheless it will
be useful later to add more tests, probably by building larger
gates by combining single-qubit and controlled single-qubit gates.

Joseph Weston authored on 15/11/2019 19:50:51
Showing 1 changed files
... ...
@@ -144,3 +144,42 @@ def test_deutch():
144 144
 
145 145
 def test_swap():
146 146
     assert np.all(qsim.gate.swap @ qsim.gate.swap == np.identity(4))
147
+
148
+
149
+@given(single_qubit_gates, n_qubits.flatmap(ket), n_qubits.flatmap(select_n_qubits(1)))
150
+def test_applying_single_gates(gate, state, selected):
151
+    qubit, = selected
152
+    n_qubits = state.shape[0].bit_length() - 1
153
+    parts = [np.identity(2)] * n_qubits
154
+    parts[qubit] = gate
155
+    big_gate = product_gate(parts)
156
+
157
+    should_be = big_gate @ state
158
+    state = qsim.gate.apply(gate, [qubit], state)
159
+
160
+    assert np.allclose(state, should_be)
161
+
162
+
163
+@given(
164
+    single_qubit_gates,
165
+    n_qubits.filter(lambda n: n > 1).flatmap(ket),
166
+    n_qubits.filter(lambda n: n > 1).flatmap(select_n_qubits(2)),
167
+)
168
+def test_applying_controlled_single_qubit_gates(gate, state, selected):
169
+    control, qubit = selected
170
+    n_qubits = state.shape[0].bit_length() - 1
171
+    # When control qubit is |0⟩ the controlled gate acts like the identity on the other qubit
172
+    parts_zero = [np.identity(2)] * n_qubits
173
+    parts_zero[control] = project_zero
174
+    parts_zero[qubit] = np.identity(2)
175
+    # When control qubit is |1⟩ the controlled gate acts like the original gate on the other qubit
176
+    parts_one = [np.identity(2)] * n_qubits
177
+    parts_one[control] = project_one
178
+    parts_one[qubit] = gate
179
+    # The total controlled gate is then the sum of these 2 product gates
180
+    big_gate = product_gate(parts_zero) + product_gate(parts_one)
181
+
182
+    should_be = big_gate @ state
183
+    state = qsim.gate.apply(qsim.gate.controlled(gate), [control, qubit], state)
184
+
185
+    assert np.allclose(state, should_be)