From 23fb6577a3dd5c6a14f8e6599eb7d4b0b9645566 Mon Sep 17 00:00:00 2001 From: Cryoris Date: Mon, 13 Jan 2020 17:32:01 +0100 Subject: [PATCH 01/20] port qc.mct tests --- test/python/circuit/test_controlled_gate.py | 118 +++++++++++++++++--- 1 file changed, 102 insertions(+), 16 deletions(-) diff --git a/test/python/circuit/test_controlled_gate.py b/test/python/circuit/test_controlled_gate.py index f6328ca1ec11..a4593d88b995 100644 --- a/test/python/circuit/test_controlled_gate.py +++ b/test/python/circuit/test_controlled_gate.py @@ -21,10 +21,13 @@ from numpy import pi import scipy from ddt import ddt, data +import itertools +from parameterized import parameterized from qiskit import QuantumRegister, QuantumCircuit, execute, BasicAer, QiskitError from qiskit.test import QiskitTestCase from qiskit.circuit import ControlledGate +from qiskit.quantum_info import state_fidelity from qiskit.quantum_info.operators.predicates import matrix_equal, is_unitary_matrix import qiskit.circuit.add_control as ac from qiskit.transpiler.passes import Unroller @@ -128,7 +131,7 @@ def test_multi_controlled_composite_gate(self): sub_q = QuantumRegister(2) cgate = QuantumCircuit(sub_q, name='cgate') cgate.h(sub_q[0]) - cgate.crz(pi/2, sub_q[0], sub_q[1]) + cgate.crz(pi / 2, sub_q[0], sub_q[1]) cgate.swap(sub_q[0], sub_q[1]) cgate.u3(0.1, 0.2, 0.3, sub_q[1]) cgate.t(sub_q[0]) @@ -138,7 +141,7 @@ def test_multi_controlled_composite_gate(self): control = QuantumRegister(num_ctrl) target = QuantumRegister(num_target) qc = QuantumCircuit(control, target) - qc.append(cont_gate, control[:]+target[:]) + qc.append(cont_gate, control[:] + target[:]) simulator = BasicAer.get_backend('unitary_simulator') op_mat = execute(cgate, simulator).result().get_unitary(0) cop_mat = _compute_control_matrix(op_mat, num_ctrl) @@ -159,7 +162,7 @@ def test_single_controlled_composite_gate(self): control = QuantumRegister(num_ctrl) target = QuantumRegister(num_target) qc = QuantumCircuit(control, target) - qc.append(cont_gate, control[:]+target[:]) + qc.append(cont_gate, control[:] + target[:]) simulator = BasicAer.get_backend('unitary_simulator') op_mat = execute(cgate, simulator).result().get_unitary(0) cop_mat = _compute_control_matrix(op_mat, num_ctrl) @@ -290,6 +293,90 @@ def test_multi_control_u1(self): self.log.info(info) self.assertTrue(matrix_equal(target, decomp, ignore_phase=True)) + @parameterized.expand( + itertools.product([1, 2, 3], ['basic']) + ) + def test_multi_control_toffoli_clean_ancillas(self, num_controls, mode): + """Test multi-control Toffoli gate with clean ancillas.""" + + # set up circuit + c = QuantumRegister(num_controls, name='c') + q_o = QuantumRegister(1, name='o') + qc = QuantumCircuit(q_o, c) + + # add ancillas if necessary + num_ancillas = 0 if num_controls <= 2 else num_controls - 2 + q_a = None + if num_ancillas > 0: + q_a = QuantumRegister(num_ancillas, name='a') + qc.add_register(q_a) + + # apply hadamard on control qubits and toffoli gate + qc.h(c) + qc.mct([c[i] for i in range(num_controls)], + q_o[0], + [q_a[i] for i in range(num_ancillas)], + mode=mode) + + # execute the circuit and obtain statevector result + backend = BasicAer.get_backend('statevector_simulator') + vec_mct = execute(qc, backend).result().get_statevector(qc) + + # compare to expectation + mat = np.eye(2 ** (num_controls + 1)) + mat[-2:, -2:] = [[0, 1], [1, 0]] + if num_ancillas > 0: + mat = np.kron(np.eye(2 ** num_ancillas), mat) + + vec_groundtruth = mat @ np.kron(np.kron( + np.array([1] + [0] * (2 ** num_ancillas - 1)), + [1 / 2 ** (num_controls / 2)] * 2 ** num_controls), [1, 0]) + + s_f = state_fidelity(vec_mct, vec_groundtruth) + self.assertAlmostEqual(s_f, 1) + + @parameterized.expand( + itertools.product([1, 2, 3, 4, 5], + ['basic-dirty-ancilla', 'advanced', 'noancilla']) + ) + def test_multi_control_toffoli_dirty_ancillas(self, num_controls, mode): + """Test multi-control Toffoli gate with dirty ancillas.""" + c = QuantumRegister(num_controls, name='c') + q_o = QuantumRegister(1, name='o') + qc = QuantumCircuit(q_o, c) + + if mode == 'basic-dirty-ancilla': + if num_controls <= 2: + num_ancillas = 0 + else: + num_ancillas = num_controls - 2 + elif mode == 'noancilla': + num_ancillas = 0 + else: + if num_controls <= 4: + num_ancillas = 0 + else: + num_ancillas = 1 + + q_a = None + if num_ancillas > 0: + q_a = QuantumRegister(num_ancillas, name='a') + qc.add_register(q_a) + + qc.mct([c[i] for i in range(num_controls)], + q_o[0], + [q_a[i] for i in range(num_ancillas)], + mode=mode) + + mat_mct = execute(qc, BasicAer.get_backend('unitary_simulator')).result().get_unitary(qc) + + mat_groundtruth = np.eye(2 ** (num_controls + 1)) + mat_groundtruth[-2:, -2:] = [[0, 1], [1, 0]] + if num_ancillas > 0: + mat_groundtruth = np.kron(np.eye(2 ** num_ancillas), mat_groundtruth) + + self.assertTrue(np.allclose(mat_mct, mat_groundtruth)) + def test_rotation_gates(self): """Test controlled rotation gates""" import qiskit.extensions.standard.u1 as u1 @@ -352,7 +439,6 @@ def test_rotation_gates(self): dag = circuit_to_dag(qc) unroller = Unroller(['u3', 'cx']) uqc = dag_to_circuit(unroller.run(dag)) - print(uqc.size()) self.log.info('%s gate count: %d', uqc.name, uqc.size()) self.assertTrue(uqc.size() <= 93) # this limit could be changed @@ -372,7 +458,7 @@ def test_inverse_circuit(self, num_ctrl_qubits): qc.h(0) qc.cx(0, 1) qc.cx(1, 2) - qc.rx(np.pi/4, [0, 1, 2]) + qc.rx(np.pi / 4, [0, 1, 2]) gate = qc.to_gate() cgate = gate.control(num_ctrl_qubits) inv_cgate = cgate.inverse() @@ -438,10 +524,10 @@ def test_all_inverses(self): try: sig = signature(cls) numargs = len([param for param in sig.parameters.values() - if param.kind == param.POSITIONAL_ONLY - or (param.kind == param.POSITIONAL_OR_KEYWORD - and param.default is param.empty)]) - args = [1]*numargs + if param.kind == param.POSITIONAL_ONLY or + (param.kind == param.POSITIONAL_OR_KEYWORD and + param.default is param.empty)]) + args = [1] * numargs gate = cls(*args) self.assertEqual(gate.inverse().control(2), @@ -457,14 +543,14 @@ def test_controlled_standard_gates(self, num_ctrl_qubits): """ gate_classes = [cls for name, cls in allGates.__dict__.items() if isinstance(cls, type)] - theta = pi/2 + theta = pi / 2 for cls in gate_classes: with self.subTest(i=cls): sig = signature(cls) numargs = len([param for param in sig.parameters.values() - if param.kind == param.POSITIONAL_ONLY - or (param.kind == param.POSITIONAL_OR_KEYWORD - and param.default is param.empty)]) + if param.kind == param.POSITIONAL_ONLY or + (param.kind == param.POSITIONAL_OR_KEYWORD and + param.default is param.empty)]) args = [theta] * numargs if cls in [MSGate, Barrier]: args[0] = 2 @@ -498,13 +584,13 @@ def _compute_control_matrix(base_mat, num_ctrl_qubits): """ num_target = int(np.log2(base_mat.shape[0])) ctrl_dim = 2**num_ctrl_qubits - ctrl_grnd = np.repeat([[1], [0]], [1, ctrl_dim-1]) + ctrl_grnd = np.repeat([[1], [0]], [1, ctrl_dim - 1]) full_mat_dim = ctrl_dim * base_mat.shape[0] full_mat = np.zeros((full_mat_dim, full_mat_dim), dtype=base_mat.dtype) ctrl_proj = np.diag(np.roll(ctrl_grnd, ctrl_dim - 1)) full_mat = (np.kron(np.eye(2**num_target), - np.eye(ctrl_dim) - ctrl_proj) - + np.kron(base_mat, ctrl_proj)) + np.eye(ctrl_dim) - ctrl_proj) + + np.kron(base_mat, ctrl_proj)) return full_mat From 08aeee71183f634c6b5cf302a50e0112d04e6558 Mon Sep 17 00:00:00 2001 From: Cryoris Date: Mon, 13 Jan 2020 18:13:33 +0100 Subject: [PATCH 02/20] port qc.mcr(x,y,z) tests --- test/python/circuit/test_controlled_gate.py | 104 +++++++++++++++++++- 1 file changed, 102 insertions(+), 2 deletions(-) diff --git a/test/python/circuit/test_controlled_gate.py b/test/python/circuit/test_controlled_gate.py index a4593d88b995..8d42a53f9e92 100644 --- a/test/python/circuit/test_controlled_gate.py +++ b/test/python/circuit/test_controlled_gate.py @@ -377,8 +377,8 @@ def test_multi_control_toffoli_dirty_ancillas(self, num_controls, mode): self.assertTrue(np.allclose(mat_mct, mat_groundtruth)) - def test_rotation_gates(self): - """Test controlled rotation gates""" + def test_single_controlled_rotation_gates(self): + """Test controlled rotation gates controlled on one qubit""" import qiskit.extensions.standard.u1 as u1 import qiskit.extensions.standard.rx as rx import qiskit.extensions.standard.ry as ry @@ -442,6 +442,106 @@ def test_rotation_gates(self): self.log.info('%s gate count: %d', uqc.name, uqc.size()) self.assertTrue(uqc.size() <= 93) # this limit could be changed + @parameterized.expand( + itertools.product([1, 2, 4], ['x', 'y', 'z'], [True, False]) + ) + def test_multi_controlled_rotation_gates(self, num_controls, base_gate_name, use_basis_gates): + """Test the multi controlled rotation gates without ancillas.""" + c = QuantumRegister(num_controls, name='c') + q_o = QuantumRegister(1, name='o') + allsubsets = list(itertools.chain(*[itertools.combinations(range(num_controls), ni) for + ni in range(num_controls + 1)])) + for subset in allsubsets: + control_int = 0 + theta = 0.871236 * pi + qc = QuantumCircuit(q_o, c) + for idx in subset: + control_int += 2**idx + qc.x(c[idx]) + + # call mcrx/mcry/mcrz + if base_gate_name == 'y': + qc.mcry(theta, [c[i] for i in range(num_controls)], q_o[0], None, mode='noancilla', + use_basis_gates=use_basis_gates) + else: # case 'x' or 'z' only support the noancilla mode and do not have this keyword + getattr(qc, 'mcr' + base_gate_name)(theta, [c[i] for i in range(num_controls)], + q_o[0], use_basis_gates=use_basis_gates) + + for idx in subset: + qc.x(c[idx]) + + mat_mcu = execute(qc, BasicAer.get_backend( + 'unitary_simulator')).result().get_unitary(qc) + + dim = 2**(num_controls + 1) + pos = dim - 2 * (control_int + 1) + mat_groundtruth = np.eye(dim, dtype=complex) + + if base_gate_name == 'x': + rot_mat = np.array([[np.cos(theta / 2), -1j * np.sin(theta / 2)], + [-1j * np.sin(theta / 2), np.cos(theta / 2)]], + dtype=complex) + elif base_gate_name == 'y': + rot_mat = np.array([[np.cos(theta / 2), -np.sin(theta / 2)], + [np.sin(theta / 2), np.cos(theta / 2)]], + dtype=complex) + else: # case 'z' + rot_mat = np.array([[1, 0], + [0, np.exp(1j * theta)]], + dtype=complex) + + mat_groundtruth[pos:pos + 2, pos:pos + 2] = rot_mat + self.assertTrue(np.allclose(mat_mcu, mat_groundtruth)) + + @parameterized.expand( + itertools.product([1, 2, 4], [True, False]) + ) + def test_multi_controlled_y_rotation_basic_mode(self, num_controls, use_basis_gates): + """Test multi controlled Y rotation using the mode 'basic'.""" + if num_controls <= 2: + num_ancillas = 0 + else: + num_ancillas = num_controls - 2 + c = QuantumRegister(num_controls, name='c') + q_o = QuantumRegister(1, name='o') + allsubsets = list(itertools.chain(*[itertools.combinations(range(num_controls), ni) for + ni in range(num_controls + 1)])) + for subset in allsubsets: + control_int = 0 + theta = 0.871236 * pi + qc = QuantumCircuit(q_o, c) + if num_ancillas > 0: + q_a = QuantumRegister(num_ancillas, name='a') + qc.add_register(q_a) + else: + q_a = None + + for idx in subset: + control_int += 2**idx + qc.x(c[idx]) + + qc.mcry(theta, [c[i] for i in range(num_controls)], q_o[0], + [q_a[i] for i in range(num_ancillas)], mode='basic', + use_basis_gates=use_basis_gates) + + for idx in subset: + qc.x(c[idx]) + + mat_mcu = execute(qc, BasicAer.get_backend( + 'unitary_simulator')).result().get_unitary(qc) + + dim = 2**(num_controls + 1) + mat_mcu = mat_mcu[:dim, :dim] + pos = dim - 2 * (control_int + 1) + mat_groundtruth = np.eye(dim, dtype=complex) + + rot_mat = np.array([[np.cos(theta / 2), -np.sin(theta / 2)], + [np.sin(theta / 2), np.cos(theta / 2)]], + dtype=complex) + + mat_groundtruth[pos:pos + 2, pos:pos + 2] = rot_mat + self.assertTrue(np.allclose(mat_mcu, mat_groundtruth)) + @data(1, 2, 3, 4) def test_inverse_x(self, num_ctrl_qubits): """test inverting ControlledGate""" From de680e0c829d494290dc0b5717b32b86bf0953b5 Mon Sep 17 00:00:00 2001 From: Cryoris Date: Tue, 14 Jan 2020 09:42:07 +0100 Subject: [PATCH 03/20] port qc.mcu1 test --- test/python/circuit/test_controlled_gate.py | 56 +++++++++++++++++---- 1 file changed, 47 insertions(+), 9 deletions(-) diff --git a/test/python/circuit/test_controlled_gate.py b/test/python/circuit/test_controlled_gate.py index 8d42a53f9e92..c4bce2c34a85 100644 --- a/test/python/circuit/test_controlled_gate.py +++ b/test/python/circuit/test_controlled_gate.py @@ -16,12 +16,12 @@ """Test Qiskit's inverse gate operation.""" import unittest +import itertools from inspect import signature import numpy as np from numpy import pi import scipy from ddt import ddt, data -import itertools from parameterized import parameterized from qiskit import QuantumRegister, QuantumCircuit, execute, BasicAer, QiskitError @@ -169,7 +169,7 @@ def test_single_controlled_composite_gate(self): ref_mat = execute(qc, simulator).result().get_unitary(0) self.assertTrue(matrix_equal(cop_mat, ref_mat, ignore_phase=True)) - def test_multi_control_u3(self): + def test_controlled_u3_matrix(self): """test multi controlled u3 gate""" import qiskit.extensions.standard.u3 as u3 import qiskit.extensions.standard.cu3 as cu3 @@ -231,7 +231,7 @@ def test_multi_control_u3(self): self.log.info(info) self.assertTrue(matrix_equal(target, decomp, ignore_phase=True)) - def test_multi_control_u1(self): + def test_controlled_u1_matrix(self): """Test multi controlled u1 gate""" import qiskit.extensions.standard.u1 as u1 import qiskit.extensions.standard.cu1 as cu1 @@ -293,10 +293,47 @@ def test_multi_control_u1(self): self.log.info(info) self.assertTrue(matrix_equal(target, decomp, ignore_phase=True)) + @parameterized.expand([[1], [2], [3], [4]]) + def test_multi_controlled_u1_matrix(self, num_controls): + """Test the matrix representation of the multi-controlled CU1 gate.""" + + # registers for the circuit + c = QuantumRegister(num_controls, name='c') + q_o = QuantumRegister(1, name='o') + + # iterate over all possible combinations of control qubits + allsubsets = list(itertools.chain(*[itertools.combinations(range(num_controls), ni) + for ni in range(num_controls + 1)])) + for subset in allsubsets: + control_int = 0 + lam = 0.3165354 * pi + qc = QuantumCircuit(q_o, c) + for idx in subset: + control_int += 2**idx + qc.x(c[idx]) + + qc.h(q_o[0]) + qc.mcu1(lam, [c[i] for i in range(num_controls)], q_o[0]) + qc.h(q_o[0]) + + for idx in subset: + qc.x(c[idx]) + + backend = BasicAer.get_backend('unitary_simulator') + mat_mcu = execute(qc, backend).result().get_unitary(qc) + + dim = 2**(num_controls + 1) + pos = dim - 2 * (control_int + 1) + mat_groundtruth = np.eye(dim, dtype=complex) + fac = np.exp(1j * lam) + mat_groundtruth[pos:pos + 2, pos:pos + 2] = [[(1 + fac) / 2, (1 - fac) / 2], + [(1 - fac) / 2, (1 + fac) / 2]] + self.assertTrue(np.allclose(mat_mcu, mat_groundtruth)) + @parameterized.expand( itertools.product([1, 2, 3], ['basic']) ) - def test_multi_control_toffoli_clean_ancillas(self, num_controls, mode): + def test_multi_control_toffoli_matrix_clean_ancillas(self, num_controls, mode): """Test multi-control Toffoli gate with clean ancillas.""" # set up circuit @@ -339,7 +376,7 @@ def test_multi_control_toffoli_clean_ancillas(self, num_controls, mode): itertools.product([1, 2, 3, 4, 5], ['basic-dirty-ancilla', 'advanced', 'noancilla']) ) - def test_multi_control_toffoli_dirty_ancillas(self, num_controls, mode): + def test_multi_control_toffoli_matrix_dirty_ancillas(self, num_controls, mode): """Test multi-control Toffoli gate with dirty ancillas.""" c = QuantumRegister(num_controls, name='c') q_o = QuantumRegister(1, name='o') @@ -445,7 +482,8 @@ def test_single_controlled_rotation_gates(self): @parameterized.expand( itertools.product([1, 2, 4], ['x', 'y', 'z'], [True, False]) ) - def test_multi_controlled_rotation_gates(self, num_controls, base_gate_name, use_basis_gates): + def test_multi_controlled_rotation_gate_matrices(self, num_controls, base_gate_name, + use_basis_gates): """Test the multi controlled rotation gates without ancillas.""" c = QuantumRegister(num_controls, name='c') q_o = QuantumRegister(1, name='o') @@ -496,7 +534,7 @@ def test_multi_controlled_rotation_gates(self, num_controls, base_gate_name, use @parameterized.expand( itertools.product([1, 2, 4], [True, False]) ) - def test_multi_controlled_y_rotation_basic_mode(self, num_controls, use_basis_gates): + def test_multi_controlled_y_rotation_matrix_basic_mode(self, num_controls, use_basis_gates): """Test multi controlled Y rotation using the mode 'basic'.""" if num_controls <= 2: num_ancillas = 0 @@ -626,7 +664,7 @@ def test_all_inverses(self): numargs = len([param for param in sig.parameters.values() if param.kind == param.POSITIONAL_ONLY or (param.kind == param.POSITIONAL_OR_KEYWORD and - param.default is param.empty)]) + param.default is param.empty)]) args = [1] * numargs gate = cls(*args) @@ -650,7 +688,7 @@ def test_controlled_standard_gates(self, num_ctrl_qubits): numargs = len([param for param in sig.parameters.values() if param.kind == param.POSITIONAL_ONLY or (param.kind == param.POSITIONAL_OR_KEYWORD and - param.default is param.empty)]) + param.default is param.empty)]) args = [theta] * numargs if cls in [MSGate, Barrier]: args[0] = 2 From 1728909216880115965c8226b6eceb6b90257dd7 Mon Sep 17 00:00:00 2001 From: Cryoris Date: Tue, 14 Jan 2020 10:01:41 +0100 Subject: [PATCH 04/20] update register names, remove unnecessary list comprehension register names are more expressive now, also removed names of register, since this is not needed. list comprehension was removed where the whole register could be passed instead. --- test/python/circuit/test_controlled_gate.py | 102 ++++++++++---------- 1 file changed, 49 insertions(+), 53 deletions(-) diff --git a/test/python/circuit/test_controlled_gate.py b/test/python/circuit/test_controlled_gate.py index c4bce2c34a85..98508266cc30 100644 --- a/test/python/circuit/test_controlled_gate.py +++ b/test/python/circuit/test_controlled_gate.py @@ -298,8 +298,8 @@ def test_multi_controlled_u1_matrix(self, num_controls): """Test the matrix representation of the multi-controlled CU1 gate.""" # registers for the circuit - c = QuantumRegister(num_controls, name='c') - q_o = QuantumRegister(1, name='o') + q_controls = QuantumRegister(num_controls) + q_target = QuantumRegister(1) # iterate over all possible combinations of control qubits allsubsets = list(itertools.chain(*[itertools.combinations(range(num_controls), ni) @@ -307,17 +307,17 @@ def test_multi_controlled_u1_matrix(self, num_controls): for subset in allsubsets: control_int = 0 lam = 0.3165354 * pi - qc = QuantumCircuit(q_o, c) + qc = QuantumCircuit(q_target, q_controls) for idx in subset: control_int += 2**idx - qc.x(c[idx]) + qc.x(q_controls[idx]) - qc.h(q_o[0]) - qc.mcu1(lam, [c[i] for i in range(num_controls)], q_o[0]) - qc.h(q_o[0]) + qc.h(q_target[0]) + qc.mcu1(lam, q_controls, q_target[0]) + qc.h(q_target[0]) for idx in subset: - qc.x(c[idx]) + qc.x(q_controls[idx]) backend = BasicAer.get_backend('unitary_simulator') mat_mcu = execute(qc, backend).result().get_unitary(qc) @@ -337,23 +337,20 @@ def test_multi_control_toffoli_matrix_clean_ancillas(self, num_controls, mode): """Test multi-control Toffoli gate with clean ancillas.""" # set up circuit - c = QuantumRegister(num_controls, name='c') - q_o = QuantumRegister(1, name='o') - qc = QuantumCircuit(q_o, c) + q_controls = QuantumRegister(num_controls) + q_target = QuantumRegister(1) + qc = QuantumCircuit(q_target, q_controls) # add ancillas if necessary num_ancillas = 0 if num_controls <= 2 else num_controls - 2 - q_a = None + q_ancillas = None if num_ancillas > 0: - q_a = QuantumRegister(num_ancillas, name='a') - qc.add_register(q_a) + q_ancillas = QuantumRegister(num_ancillas) + qc.add_register(q_ancillas) # apply hadamard on control qubits and toffoli gate - qc.h(c) - qc.mct([c[i] for i in range(num_controls)], - q_o[0], - [q_a[i] for i in range(num_ancillas)], - mode=mode) + qc.h(q_controls) + qc.mct(q_controls, q_target[0], q_ancillas, mode=mode) # execute the circuit and obtain statevector result backend = BasicAer.get_backend('statevector_simulator') @@ -378,9 +375,9 @@ def test_multi_control_toffoli_matrix_clean_ancillas(self, num_controls, mode): ) def test_multi_control_toffoli_matrix_dirty_ancillas(self, num_controls, mode): """Test multi-control Toffoli gate with dirty ancillas.""" - c = QuantumRegister(num_controls, name='c') - q_o = QuantumRegister(1, name='o') - qc = QuantumCircuit(q_o, c) + q_controls = QuantumRegister(num_controls) + q_target = QuantumRegister(1) + qc = QuantumCircuit(q_target, q_controls) if mode == 'basic-dirty-ancilla': if num_controls <= 2: @@ -395,15 +392,12 @@ def test_multi_control_toffoli_matrix_dirty_ancillas(self, num_controls, mode): else: num_ancillas = 1 - q_a = None + q_ancillas = None if num_ancillas > 0: - q_a = QuantumRegister(num_ancillas, name='a') - qc.add_register(q_a) + q_ancillas = QuantumRegister(num_ancillas) + qc.add_register(q_ancillas) - qc.mct([c[i] for i in range(num_controls)], - q_o[0], - [q_a[i] for i in range(num_ancillas)], - mode=mode) + qc.mct(q_controls, q_target[0], q_ancillas, mode=mode) mat_mct = execute(qc, BasicAer.get_backend('unitary_simulator')).result().get_unitary(qc) @@ -485,31 +479,31 @@ def test_single_controlled_rotation_gates(self): def test_multi_controlled_rotation_gate_matrices(self, num_controls, base_gate_name, use_basis_gates): """Test the multi controlled rotation gates without ancillas.""" - c = QuantumRegister(num_controls, name='c') - q_o = QuantumRegister(1, name='o') + q_controls = QuantumRegister(num_controls) + q_target = QuantumRegister(1) allsubsets = list(itertools.chain(*[itertools.combinations(range(num_controls), ni) for ni in range(num_controls + 1)])) for subset in allsubsets: control_int = 0 theta = 0.871236 * pi - qc = QuantumCircuit(q_o, c) + qc = QuantumCircuit(q_target, q_controls) for idx in subset: control_int += 2**idx - qc.x(c[idx]) + qc.x(q_controls[idx]) # call mcrx/mcry/mcrz if base_gate_name == 'y': - qc.mcry(theta, [c[i] for i in range(num_controls)], q_o[0], None, mode='noancilla', + qc.mcry(theta, q_controls, q_target[0], None, mode='noancilla', use_basis_gates=use_basis_gates) else: # case 'x' or 'z' only support the noancilla mode and do not have this keyword - getattr(qc, 'mcr' + base_gate_name)(theta, [c[i] for i in range(num_controls)], - q_o[0], use_basis_gates=use_basis_gates) + getattr(qc, 'mcr' + base_gate_name)(theta, q_controls, q_target[0], + use_basis_gates=use_basis_gates) for idx in subset: - qc.x(c[idx]) + qc.x(q_controls[idx]) - mat_mcu = execute(qc, BasicAer.get_backend( - 'unitary_simulator')).result().get_unitary(qc) + backend = BasicAer.get_backend('unitary_simulator') + mat_mcu = execute(qc, backend).result().get_unitary(qc) dim = 2**(num_controls + 1) pos = dim - 2 * (control_int + 1) @@ -536,37 +530,39 @@ def test_multi_controlled_rotation_gate_matrices(self, num_controls, base_gate_n ) def test_multi_controlled_y_rotation_matrix_basic_mode(self, num_controls, use_basis_gates): """Test multi controlled Y rotation using the mode 'basic'.""" + + # get the number of required ancilla qubits if num_controls <= 2: num_ancillas = 0 else: num_ancillas = num_controls - 2 - c = QuantumRegister(num_controls, name='c') - q_o = QuantumRegister(1, name='o') + + q_controls = QuantumRegister(num_controls) + q_target = QuantumRegister(1) allsubsets = list(itertools.chain(*[itertools.combinations(range(num_controls), ni) for ni in range(num_controls + 1)])) for subset in allsubsets: control_int = 0 theta = 0.871236 * pi - qc = QuantumCircuit(q_o, c) + qc = QuantumCircuit(q_target, q_controls) if num_ancillas > 0: - q_a = QuantumRegister(num_ancillas, name='a') - qc.add_register(q_a) + q_ancillas = QuantumRegister(num_ancillas) + qc.add_register(q_ancillas) else: - q_a = None + q_ancillas = None for idx in subset: control_int += 2**idx - qc.x(c[idx]) + qc.x(q_controls[idx]) - qc.mcry(theta, [c[i] for i in range(num_controls)], q_o[0], - [q_a[i] for i in range(num_ancillas)], mode='basic', + qc.mcry(theta, q_controls, q_target[0], q_ancillas, mode='basic', use_basis_gates=use_basis_gates) for idx in subset: - qc.x(c[idx]) + qc.x(q_controls[idx]) - mat_mcu = execute(qc, BasicAer.get_backend( - 'unitary_simulator')).result().get_unitary(qc) + backend = BasicAer.get_backend('unitary_simulator') + mat_mcu = execute(qc, backend).result().get_unitary(qc) dim = 2**(num_controls + 1) mat_mcu = mat_mcu[:dim, :dim] @@ -664,7 +660,7 @@ def test_all_inverses(self): numargs = len([param for param in sig.parameters.values() if param.kind == param.POSITIONAL_ONLY or (param.kind == param.POSITIONAL_OR_KEYWORD and - param.default is param.empty)]) + param.default is param.empty)]) args = [1] * numargs gate = cls(*args) @@ -688,7 +684,7 @@ def test_controlled_standard_gates(self, num_ctrl_qubits): numargs = len([param for param in sig.parameters.values() if param.kind == param.POSITIONAL_ONLY or (param.kind == param.POSITIONAL_OR_KEYWORD and - param.default is param.empty)]) + param.default is param.empty)]) args = [theta] * numargs if cls in [MSGate, Barrier]: args[0] = 2 From 8ca5592bd0775faac6a8eb28abdba94ac5c2dd97 Mon Sep 17 00:00:00 2001 From: Cryoris Date: Tue, 14 Jan 2020 11:08:34 +0100 Subject: [PATCH 05/20] docstrings have complete sentences --- test/python/circuit/test_controlled_gate.py | 68 ++++++++++----------- 1 file changed, 33 insertions(+), 35 deletions(-) diff --git a/test/python/circuit/test_controlled_gate.py b/test/python/circuit/test_controlled_gate.py index 98508266cc30..b33c36ae1348 100644 --- a/test/python/circuit/test_controlled_gate.py +++ b/test/python/circuit/test_controlled_gate.py @@ -46,60 +46,60 @@ @ddt class TestControlledGate(QiskitTestCase): - """ControlledGate tests.""" + """Tests for controlled gates and the ControlledGate class.""" def test_controlled_x(self): - """Test creation of controlled x gate""" + """Test the creation of a controlled X gate.""" self.assertEqual(XGate().control(), CnotGate()) def test_controlled_y(self): - """Test creation of controlled y gate""" + """Test the creation of a controlled Y gate.""" self.assertEqual(YGate().control(), CyGate()) def test_controlled_z(self): - """Test creation of controlled z gate""" + """Test the creation of a controlled Z gate.""" self.assertEqual(ZGate().control(), CzGate()) def test_controlled_h(self): - """Test creation of controlled h gate""" + """Test the creation of a controlled H gate.""" self.assertEqual(HGate().control(), CHGate()) def test_controlled_u1(self): - """Test creation of controlled u1 gate""" + """Test the creation of a controlled U1 gate.""" theta = 0.5 self.assertEqual(U1Gate(theta).control(), Cu1Gate(theta)) def test_controlled_rz(self): - """Test creation of controlled rz gate""" + """Test the creation of a controlled RZ gate.""" theta = 0.5 self.assertEqual(RZGate(theta).control(), CrzGate(theta)) def test_controlled_ry(self): - """Test creation of controlled ry gate""" + """Test the creation of a controlled RY gate.""" theta = 0.5 self.assertEqual(RYGate(theta).control(), CryGate(theta)) def test_controlled_rx(self): - """Test creation of controlled rx gate""" + """Test the creation of a controlled RX gate.""" theta = 0.5 self.assertEqual(RXGate(theta).control(), CrxGate(theta)) def test_controlled_u3(self): - """Test creation of controlled u3 gate""" + """Test the creation of a controlled U3 gate.""" theta, phi, lamb = 0.1, 0.2, 0.3 self.assertEqual(U3Gate(theta, phi, lamb).control(), Cu3Gate(theta, phi, lamb)) def test_controlled_cx(self): - """Test creation of controlled cx gate""" + """Test the creation of a controlled CX gate.""" self.assertEqual(CnotGate().control(), ToffoliGate()) def test_controlled_swap(self): - """Test creation of controlled swap gate""" + """Test the creation of a controlled Swap gate.""" self.assertEqual(SwapGate().control(), FredkinGate()) def test_circuit_append(self): - """Test appending controlled gate to quantum circuit""" + """Test appending a controlled gate to a quantum circuit.""" circ = QuantumCircuit(5) inst = CnotGate() circ.append(inst.control(), qargs=[0, 2, 1]) @@ -117,15 +117,15 @@ def test_circuit_append(self): gate = instr[0] self.assertTrue(isinstance(gate, ControlledGate)) - def test_definition_specification(self): - """Test instantiation with explicit definition""" + def test_swap_definition_specification(self): + """Test the instantiation of a controlled swap gate with explicit definition.""" swap = SwapGate() cswap = ControlledGate('cswap', 3, [], num_ctrl_qubits=1, definition=swap.definition) self.assertEqual(swap.definition, cswap.definition) def test_multi_controlled_composite_gate(self): - """Test multi controlled composite gate""" + """Test a multi controlled composite gate. """ num_ctrl = 3 # create composite gate sub_q = QuantumRegister(2) @@ -149,7 +149,7 @@ def test_multi_controlled_composite_gate(self): self.assertTrue(matrix_equal(cop_mat, ref_mat, ignore_phase=True)) def test_single_controlled_composite_gate(self): - """Test singly controlled composite gate""" + """Test a singly controlled composite gate.""" num_ctrl = 1 # create composite gate sub_q = QuantumRegister(2) @@ -170,7 +170,7 @@ def test_single_controlled_composite_gate(self): self.assertTrue(matrix_equal(cop_mat, ref_mat, ignore_phase=True)) def test_controlled_u3_matrix(self): - """test multi controlled u3 gate""" + """Test the matrix representation of the controlled and controlled-controlled U3 gate.""" import qiskit.extensions.standard.u3 as u3 import qiskit.extensions.standard.cu3 as cu3 @@ -232,7 +232,7 @@ def test_controlled_u3_matrix(self): self.assertTrue(matrix_equal(target, decomp, ignore_phase=True)) def test_controlled_u1_matrix(self): - """Test multi controlled u1 gate""" + """Test the matrix representation of the controlled and controlled-controlled U1 gate.""" import qiskit.extensions.standard.u1 as u1 import qiskit.extensions.standard.cu1 as cu1 @@ -293,7 +293,7 @@ def test_controlled_u1_matrix(self): self.log.info(info) self.assertTrue(matrix_equal(target, decomp, ignore_phase=True)) - @parameterized.expand([[1], [2], [3], [4]]) + @data(1, 2, 3, 4) def test_multi_controlled_u1_matrix(self, num_controls): """Test the matrix representation of the multi-controlled CU1 gate.""" @@ -334,7 +334,7 @@ def test_multi_controlled_u1_matrix(self, num_controls): itertools.product([1, 2, 3], ['basic']) ) def test_multi_control_toffoli_matrix_clean_ancillas(self, num_controls, mode): - """Test multi-control Toffoli gate with clean ancillas.""" + """Test the multi-control Toffoli gate with clean ancillas.""" # set up circuit q_controls = QuantumRegister(num_controls) @@ -374,7 +374,7 @@ def test_multi_control_toffoli_matrix_clean_ancillas(self, num_controls, mode): ['basic-dirty-ancilla', 'advanced', 'noancilla']) ) def test_multi_control_toffoli_matrix_dirty_ancillas(self, num_controls, mode): - """Test multi-control Toffoli gate with dirty ancillas.""" + """Test the multi-control Toffoli gate with dirty ancillas.""" q_controls = QuantumRegister(num_controls) q_target = QuantumRegister(1) qc = QuantumCircuit(q_target, q_controls) @@ -409,7 +409,7 @@ def test_multi_control_toffoli_matrix_dirty_ancillas(self, num_controls, mode): self.assertTrue(np.allclose(mat_mct, mat_groundtruth)) def test_single_controlled_rotation_gates(self): - """Test controlled rotation gates controlled on one qubit""" + """Test the controlled rotation gates controlled on one qubit.""" import qiskit.extensions.standard.u1 as u1 import qiskit.extensions.standard.rx as rx import qiskit.extensions.standard.ry as ry @@ -529,7 +529,7 @@ def test_multi_controlled_rotation_gate_matrices(self, num_controls, base_gate_n itertools.product([1, 2, 4], [True, False]) ) def test_multi_controlled_y_rotation_matrix_basic_mode(self, num_controls, use_basis_gates): - """Test multi controlled Y rotation using the mode 'basic'.""" + """Test the multi controlled Y rotation using the mode 'basic'.""" # get the number of required ancilla qubits if num_controls <= 2: @@ -578,7 +578,7 @@ def test_multi_controlled_y_rotation_matrix_basic_mode(self, num_controls, use_b @data(1, 2, 3, 4) def test_inverse_x(self, num_ctrl_qubits): - """test inverting ControlledGate""" + """Test inverting the controlled X gate.""" cnx = XGate().control(num_ctrl_qubits) inv_cnx = cnx.inverse() result = Operator(cnx).compose(Operator(inv_cnx)) @@ -587,7 +587,7 @@ def test_inverse_x(self, num_ctrl_qubits): @data(1, 2, 3) def test_inverse_circuit(self, num_ctrl_qubits): - """test inverting ControlledGate""" + """Test inverting a controlled gate based on a circuit definition.""" qc = QuantumCircuit(3) qc.h(0) qc.cx(0, 1) @@ -602,7 +602,7 @@ def test_inverse_circuit(self, num_ctrl_qubits): @data(1, 2, 3, 4, 5) def test_controlled_unitary(self, num_ctrl_qubits): - """test controlled unitary""" + """Test the matrix data of an Operator, which is based on a controlled gate.""" num_target = 1 q_target = QuantumRegister(num_target) qc1 = QuantumCircuit(q_target) @@ -621,7 +621,7 @@ def test_controlled_unitary(self, num_ctrl_qubits): @data(1, 2, 3, 4, 5) def test_controlled_random_unitary(self, num_ctrl_qubits): - """test controlled unitary""" + """Test the matrix data of an Operator based on a random UnitaryGate.""" num_target = 2 base_gate = UnitaryGate(scipy.stats.unitary_group.rvs(num_target)) base_mat = base_gate.to_matrix() @@ -632,8 +632,8 @@ def test_controlled_random_unitary(self, num_ctrl_qubits): def test_base_gate_setting(self): """ - Test all gates in standard extensions which are of type ControlledGate - have a base gate setting. + Test all gates in standard extensions which are of type ControlledGate and have a base gate + setting. """ params = [0.1 * i for i in range(10)] for gate_class in ControlledGate.__subclasses__(): @@ -645,8 +645,8 @@ def test_base_gate_setting(self): def test_all_inverses(self): """ - Test all gates in standard extensions except those that cannot be - controlled or are being deprecated. + Test all gates in standard extensions except those that cannot be controlled or are being + deprecated. """ gate_classes = [cls for name, cls in allGates.__dict__.items() if isinstance(cls, type)] @@ -672,9 +672,7 @@ def test_all_inverses(self): @data(1, 2, 3) def test_controlled_standard_gates(self, num_ctrl_qubits): - """ - Test controlled versions of all standard gates. - """ + """Test the controlled versions of all standard gates.""" gate_classes = [cls for name, cls in allGates.__dict__.items() if isinstance(cls, type)] theta = pi / 2 From 8a5890260f48d992671c612f6801fe098cecb30f Mon Sep 17 00:00:00 2001 From: Cryoris Date: Tue, 14 Jan 2020 11:59:35 +0100 Subject: [PATCH 06/20] fix lint, remove "parameterized" dependency --- test/python/circuit/test_controlled_gate.py | 36 +++++++++++---------- 1 file changed, 19 insertions(+), 17 deletions(-) diff --git a/test/python/circuit/test_controlled_gate.py b/test/python/circuit/test_controlled_gate.py index b33c36ae1348..1d0bebc5cc31 100644 --- a/test/python/circuit/test_controlled_gate.py +++ b/test/python/circuit/test_controlled_gate.py @@ -21,8 +21,7 @@ import numpy as np from numpy import pi import scipy -from ddt import ddt, data -from parameterized import parameterized +from ddt import ddt, data, unpack from qiskit import QuantumRegister, QuantumCircuit, execute, BasicAer, QiskitError from qiskit.test import QiskitTestCase @@ -330,9 +329,10 @@ def test_multi_controlled_u1_matrix(self, num_controls): [(1 - fac) / 2, (1 + fac) / 2]] self.assertTrue(np.allclose(mat_mcu, mat_groundtruth)) - @parameterized.expand( - itertools.product([1, 2, 3], ['basic']) - ) + @unpack + @data(*itertools.product( + [1, 2, 3], ['basic'] + )) def test_multi_control_toffoli_matrix_clean_ancillas(self, num_controls, mode): """Test the multi-control Toffoli gate with clean ancillas.""" @@ -369,10 +369,10 @@ def test_multi_control_toffoli_matrix_clean_ancillas(self, num_controls, mode): s_f = state_fidelity(vec_mct, vec_groundtruth) self.assertAlmostEqual(s_f, 1) - @parameterized.expand( - itertools.product([1, 2, 3, 4, 5], - ['basic-dirty-ancilla', 'advanced', 'noancilla']) - ) + @unpack + @data(*itertools.product( + [1, 2, 3, 4, 5], ['basic-dirty-ancilla', 'advanced', 'noancilla'] + )) def test_multi_control_toffoli_matrix_dirty_ancillas(self, num_controls, mode): """Test the multi-control Toffoli gate with dirty ancillas.""" q_controls = QuantumRegister(num_controls) @@ -473,9 +473,10 @@ def test_single_controlled_rotation_gates(self): self.log.info('%s gate count: %d', uqc.name, uqc.size()) self.assertTrue(uqc.size() <= 93) # this limit could be changed - @parameterized.expand( - itertools.product([1, 2, 4], ['x', 'y', 'z'], [True, False]) - ) + @unpack + @data(*itertools.product( + [1, 2, 4], ['x', 'y', 'z'], [True, False] + )) def test_multi_controlled_rotation_gate_matrices(self, num_controls, base_gate_name, use_basis_gates): """Test the multi controlled rotation gates without ancillas.""" @@ -525,9 +526,10 @@ def test_multi_controlled_rotation_gate_matrices(self, num_controls, base_gate_n mat_groundtruth[pos:pos + 2, pos:pos + 2] = rot_mat self.assertTrue(np.allclose(mat_mcu, mat_groundtruth)) - @parameterized.expand( - itertools.product([1, 2, 4], [True, False]) - ) + @unpack + @data(*itertools.product( + [1, 2, 4], [True, False] + )) def test_multi_controlled_y_rotation_matrix_basic_mode(self, num_controls, use_basis_gates): """Test the multi controlled Y rotation using the mode 'basic'.""" @@ -660,7 +662,7 @@ def test_all_inverses(self): numargs = len([param for param in sig.parameters.values() if param.kind == param.POSITIONAL_ONLY or (param.kind == param.POSITIONAL_OR_KEYWORD and - param.default is param.empty)]) + param.default is param.empty)]) args = [1] * numargs gate = cls(*args) @@ -682,7 +684,7 @@ def test_controlled_standard_gates(self, num_ctrl_qubits): numargs = len([param for param in sig.parameters.values() if param.kind == param.POSITIONAL_ONLY or (param.kind == param.POSITIONAL_OR_KEYWORD and - param.default is param.empty)]) + param.default is param.empty)]) args = [theta] * numargs if cls in [MSGate, Barrier]: args[0] = 2 From 90101d5ced1737774fccf0bbfadd1d8e41e28d34 Mon Sep 17 00:00:00 2001 From: Cryoris Date: Wed, 15 Jan 2020 16:13:25 +0100 Subject: [PATCH 07/20] use @combine instead of @unpack@data(itertools)) --- test/python/circuit/test_controlled_gate.py | 25 +++++++-------------- 1 file changed, 8 insertions(+), 17 deletions(-) diff --git a/test/python/circuit/test_controlled_gate.py b/test/python/circuit/test_controlled_gate.py index 1d0bebc5cc31..0de9f8821fc1 100644 --- a/test/python/circuit/test_controlled_gate.py +++ b/test/python/circuit/test_controlled_gate.py @@ -21,7 +21,8 @@ import numpy as np from numpy import pi import scipy -from ddt import ddt, data, unpack +from test import combine +from ddt import ddt, data from qiskit import QuantumRegister, QuantumCircuit, execute, BasicAer, QiskitError from qiskit.test import QiskitTestCase @@ -329,10 +330,7 @@ def test_multi_controlled_u1_matrix(self, num_controls): [(1 - fac) / 2, (1 + fac) / 2]] self.assertTrue(np.allclose(mat_mcu, mat_groundtruth)) - @unpack - @data(*itertools.product( - [1, 2, 3], ['basic'] - )) + @combine(num_controls=[1, 2, 3], mode=['basic']) def test_multi_control_toffoli_matrix_clean_ancillas(self, num_controls, mode): """Test the multi-control Toffoli gate with clean ancillas.""" @@ -369,10 +367,7 @@ def test_multi_control_toffoli_matrix_clean_ancillas(self, num_controls, mode): s_f = state_fidelity(vec_mct, vec_groundtruth) self.assertAlmostEqual(s_f, 1) - @unpack - @data(*itertools.product( - [1, 2, 3, 4, 5], ['basic-dirty-ancilla', 'advanced', 'noancilla'] - )) + @combine(num_controls=[1, 2, 3, 4, 5], mode=['basic-dirty-ancilla', 'advanced', 'noancilla']) def test_multi_control_toffoli_matrix_dirty_ancillas(self, num_controls, mode): """Test the multi-control Toffoli gate with dirty ancillas.""" q_controls = QuantumRegister(num_controls) @@ -473,10 +468,9 @@ def test_single_controlled_rotation_gates(self): self.log.info('%s gate count: %d', uqc.name, uqc.size()) self.assertTrue(uqc.size() <= 93) # this limit could be changed - @unpack - @data(*itertools.product( - [1, 2, 4], ['x', 'y', 'z'], [True, False] - )) + @combine(num_controls=[1, 2, 4], + base_gate_name=['x', 'y', 'z'], + use_basis_gates=[True, False]) def test_multi_controlled_rotation_gate_matrices(self, num_controls, base_gate_name, use_basis_gates): """Test the multi controlled rotation gates without ancillas.""" @@ -526,10 +520,7 @@ def test_multi_controlled_rotation_gate_matrices(self, num_controls, base_gate_n mat_groundtruth[pos:pos + 2, pos:pos + 2] = rot_mat self.assertTrue(np.allclose(mat_mcu, mat_groundtruth)) - @unpack - @data(*itertools.product( - [1, 2, 4], [True, False] - )) + @combine(num_controls=[1, 2, 4], use_basis_gates=[True, False]) def test_multi_controlled_y_rotation_matrix_basic_mode(self, num_controls, use_basis_gates): """Test the multi controlled Y rotation using the mode 'basic'.""" From 67948b9f887b3d8167b1125bf7116c4dfa93e85d Mon Sep 17 00:00:00 2001 From: Cryoris Date: Fri, 17 Jan 2020 13:30:25 +0100 Subject: [PATCH 08/20] fix import order --- test/python/circuit/test_controlled_gate.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/python/circuit/test_controlled_gate.py b/test/python/circuit/test_controlled_gate.py index 0de9f8821fc1..5be0c45d8e65 100644 --- a/test/python/circuit/test_controlled_gate.py +++ b/test/python/circuit/test_controlled_gate.py @@ -18,10 +18,10 @@ import unittest import itertools from inspect import signature +from test import combine import numpy as np from numpy import pi import scipy -from test import combine from ddt import ddt, data from qiskit import QuantumRegister, QuantumCircuit, execute, BasicAer, QiskitError From 39067ec80b45f2158d89c0fee2b800ae1aa9b061 Mon Sep 17 00:00:00 2001 From: Luciano Bello Date: Wed, 22 Jan 2020 12:56:10 -0300 Subject: [PATCH 09/20] self.assertTrue(np.allclose to assert_allclose --- test/python/circuit/test_controlled_gate.py | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/test/python/circuit/test_controlled_gate.py b/test/python/circuit/test_controlled_gate.py index 5be0c45d8e65..38985235ca94 100644 --- a/test/python/circuit/test_controlled_gate.py +++ b/test/python/circuit/test_controlled_gate.py @@ -21,6 +21,7 @@ from test import combine import numpy as np from numpy import pi +from numpy.testing import assert_allclose import scipy from ddt import ddt, data @@ -328,7 +329,7 @@ def test_multi_controlled_u1_matrix(self, num_controls): fac = np.exp(1j * lam) mat_groundtruth[pos:pos + 2, pos:pos + 2] = [[(1 + fac) / 2, (1 - fac) / 2], [(1 - fac) / 2, (1 + fac) / 2]] - self.assertTrue(np.allclose(mat_mcu, mat_groundtruth)) + assert_allclose(mat_mcu, mat_groundtruth) @combine(num_controls=[1, 2, 3], mode=['basic']) def test_multi_control_toffoli_matrix_clean_ancillas(self, num_controls, mode): @@ -401,7 +402,7 @@ def test_multi_control_toffoli_matrix_dirty_ancillas(self, num_controls, mode): if num_ancillas > 0: mat_groundtruth = np.kron(np.eye(2 ** num_ancillas), mat_groundtruth) - self.assertTrue(np.allclose(mat_mct, mat_groundtruth)) + assert_allclose(mat_mct, mat_groundtruth) def test_single_controlled_rotation_gates(self): """Test the controlled rotation gates controlled on one qubit.""" @@ -518,7 +519,7 @@ def test_multi_controlled_rotation_gate_matrices(self, num_controls, base_gate_n dtype=complex) mat_groundtruth[pos:pos + 2, pos:pos + 2] = rot_mat - self.assertTrue(np.allclose(mat_mcu, mat_groundtruth)) + assert_allclose(mat_mcu, mat_groundtruth) @combine(num_controls=[1, 2, 4], use_basis_gates=[True, False]) def test_multi_controlled_y_rotation_matrix_basic_mode(self, num_controls, use_basis_gates): @@ -567,7 +568,7 @@ def test_multi_controlled_y_rotation_matrix_basic_mode(self, num_controls, use_b dtype=complex) mat_groundtruth[pos:pos + 2, pos:pos + 2] = rot_mat - self.assertTrue(np.allclose(mat_mcu, mat_groundtruth)) + assert_allclose(mat_mcu, mat_groundtruth) @data(1, 2, 3, 4) def test_inverse_x(self, num_ctrl_qubits): From dfd6a8465346a5ff59946f591d120d7efd3b389d Mon Sep 17 00:00:00 2001 From: Luciano Bello Date: Thu, 23 Jan 2020 12:29:52 -0300 Subject: [PATCH 10/20] atol as np.allclose --- test/python/circuit/test_controlled_gate.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/python/circuit/test_controlled_gate.py b/test/python/circuit/test_controlled_gate.py index 38985235ca94..13f2a5d21396 100644 --- a/test/python/circuit/test_controlled_gate.py +++ b/test/python/circuit/test_controlled_gate.py @@ -402,7 +402,7 @@ def test_multi_control_toffoli_matrix_dirty_ancillas(self, num_controls, mode): if num_ancillas > 0: mat_groundtruth = np.kron(np.eye(2 ** num_ancillas), mat_groundtruth) - assert_allclose(mat_mct, mat_groundtruth) + assert_allclose(mat_mct, mat_groundtruth, atol=1e-08) def test_single_controlled_rotation_gates(self): """Test the controlled rotation gates controlled on one qubit.""" From 81edd727c575020fab4de8e4c4338477c68ebc58 Mon Sep 17 00:00:00 2001 From: Luciano Bello Date: Thu, 23 Jan 2020 12:49:22 -0300 Subject: [PATCH 11/20] unfold test_multi_control_toffoli_matrix_dirty_ancillas modes --- test/python/circuit/test_controlled_gate.py | 62 ++++++++++++++++----- 1 file changed, 47 insertions(+), 15 deletions(-) diff --git a/test/python/circuit/test_controlled_gate.py b/test/python/circuit/test_controlled_gate.py index 13f2a5d21396..df2a0571c7df 100644 --- a/test/python/circuit/test_controlled_gate.py +++ b/test/python/circuit/test_controlled_gate.py @@ -368,32 +368,48 @@ def test_multi_control_toffoli_matrix_clean_ancillas(self, num_controls, mode): s_f = state_fidelity(vec_mct, vec_groundtruth) self.assertAlmostEqual(s_f, 1) - @combine(num_controls=[1, 2, 3, 4, 5], mode=['basic-dirty-ancilla', 'advanced', 'noancilla']) - def test_multi_control_toffoli_matrix_dirty_ancillas(self, num_controls, mode): - """Test the multi-control Toffoli gate with dirty ancillas.""" + @data(1, 2, 3, 4, 5) + def test_multi_control_toffoli_matrix_basic_dirty_ancillas(self, num_controls): + """Test the multi-control Toffoli gate with dirty ancillas (basic-dirty-ancilla).""" q_controls = QuantumRegister(num_controls) q_target = QuantumRegister(1) qc = QuantumCircuit(q_target, q_controls) - if mode == 'basic-dirty-ancilla': - if num_controls <= 2: - num_ancillas = 0 - else: - num_ancillas = num_controls - 2 - elif mode == 'noancilla': + q_ancillas = None + if num_controls <= 2: num_ancillas = 0 else: - if num_controls <= 4: - num_ancillas = 0 - else: - num_ancillas = 1 + num_ancillas = num_controls - 2 + q_ancillas = QuantumRegister(num_ancillas) + qc.add_register(q_ancillas) - q_ancillas = None + qc.mct(q_controls, q_target[0], q_ancillas, mode='basic-dirty-ancilla') + + mat_mct = execute(qc, BasicAer.get_backend('unitary_simulator')).result().get_unitary(qc) + + mat_groundtruth = np.eye(2 ** (num_controls + 1)) + mat_groundtruth[-2:, -2:] = [[0, 1], [1, 0]] if num_ancillas > 0: + mat_groundtruth = np.kron(np.eye(2 ** num_ancillas), mat_groundtruth) + + assert_allclose(mat_mct, mat_groundtruth, atol=1e-08) + + @data(1, 2, 3, 4, 5) + def test_multi_control_toffoli_matrix_advanced_dirty_ancillas(self, num_controls): + """Test the multi-control Toffoli gate with dirty ancillas (advanced).""" + q_controls = QuantumRegister(num_controls) + q_target = QuantumRegister(1) + qc = QuantumCircuit(q_target, q_controls) + + q_ancillas = None + if num_controls <= 4: + num_ancillas = 0 + else: + num_ancillas = 1 q_ancillas = QuantumRegister(num_ancillas) qc.add_register(q_ancillas) - qc.mct(q_controls, q_target[0], q_ancillas, mode=mode) + qc.mct(q_controls, q_target[0], q_ancillas, mode='advanced') mat_mct = execute(qc, BasicAer.get_backend('unitary_simulator')).result().get_unitary(qc) @@ -404,6 +420,22 @@ def test_multi_control_toffoli_matrix_dirty_ancillas(self, num_controls, mode): assert_allclose(mat_mct, mat_groundtruth, atol=1e-08) + @data(1, 2, 3, 4, 5) + def test_multi_control_toffoli_matrix_noancilla_dirty_ancillas(self, num_controls): + """Test the multi-control Toffoli gate with dirty ancillas (noancilla).""" + q_controls = QuantumRegister(num_controls) + q_target = QuantumRegister(1) + qc = QuantumCircuit(q_target, q_controls) + + qc.mct(q_controls, q_target[0], None, mode='noancilla') + + mat_mct = execute(qc, BasicAer.get_backend('unitary_simulator')).result().get_unitary(qc) + + mat_groundtruth = np.eye(2 ** (num_controls + 1)) + mat_groundtruth[-2:, -2:] = [[0, 1], [1, 0]] + + assert_allclose(mat_mct, mat_groundtruth, atol=1e-08) + def test_single_controlled_rotation_gates(self): """Test the controlled rotation gates controlled on one qubit.""" import qiskit.extensions.standard.u1 as u1 From fe35152c53fad81e34570dd1b9f1b69703c505c7 Mon Sep 17 00:00:00 2001 From: Luciano Bello Date: Thu, 23 Jan 2020 12:56:26 -0300 Subject: [PATCH 12/20] no need for combine in test_multi_control_toffoli_matrix_clean_ancillas --- test/python/circuit/test_controlled_gate.py | 22 ++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/test/python/circuit/test_controlled_gate.py b/test/python/circuit/test_controlled_gate.py index df2a0571c7df..0df25ac38355 100644 --- a/test/python/circuit/test_controlled_gate.py +++ b/test/python/circuit/test_controlled_gate.py @@ -310,7 +310,7 @@ def test_multi_controlled_u1_matrix(self, num_controls): lam = 0.3165354 * pi qc = QuantumCircuit(q_target, q_controls) for idx in subset: - control_int += 2**idx + control_int += 2 ** idx qc.x(q_controls[idx]) qc.h(q_target[0]) @@ -323,7 +323,7 @@ def test_multi_controlled_u1_matrix(self, num_controls): backend = BasicAer.get_backend('unitary_simulator') mat_mcu = execute(qc, backend).result().get_unitary(qc) - dim = 2**(num_controls + 1) + dim = 2 ** (num_controls + 1) pos = dim - 2 * (control_int + 1) mat_groundtruth = np.eye(dim, dtype=complex) fac = np.exp(1j * lam) @@ -331,8 +331,8 @@ def test_multi_controlled_u1_matrix(self, num_controls): [(1 - fac) / 2, (1 + fac) / 2]] assert_allclose(mat_mcu, mat_groundtruth) - @combine(num_controls=[1, 2, 3], mode=['basic']) - def test_multi_control_toffoli_matrix_clean_ancillas(self, num_controls, mode): + @data(1, 2, 3) + def test_multi_control_toffoli_matrix_clean_ancillas(self, num_controls): """Test the multi-control Toffoli gate with clean ancillas.""" # set up circuit @@ -349,7 +349,7 @@ def test_multi_control_toffoli_matrix_clean_ancillas(self, num_controls, mode): # apply hadamard on control qubits and toffoli gate qc.h(q_controls) - qc.mct(q_controls, q_target[0], q_ancillas, mode=mode) + qc.mct(q_controls, q_target[0], q_ancillas, mode='basic') # execute the circuit and obtain statevector result backend = BasicAer.get_backend('statevector_simulator') @@ -516,7 +516,7 @@ def test_multi_controlled_rotation_gate_matrices(self, num_controls, base_gate_n theta = 0.871236 * pi qc = QuantumCircuit(q_target, q_controls) for idx in subset: - control_int += 2**idx + control_int += 2 ** idx qc.x(q_controls[idx]) # call mcrx/mcry/mcrz @@ -533,7 +533,7 @@ def test_multi_controlled_rotation_gate_matrices(self, num_controls, base_gate_n backend = BasicAer.get_backend('unitary_simulator') mat_mcu = execute(qc, backend).result().get_unitary(qc) - dim = 2**(num_controls + 1) + dim = 2 ** (num_controls + 1) pos = dim - 2 * (control_int + 1) mat_groundtruth = np.eye(dim, dtype=complex) @@ -578,7 +578,7 @@ def test_multi_controlled_y_rotation_matrix_basic_mode(self, num_controls, use_b q_ancillas = None for idx in subset: - control_int += 2**idx + control_int += 2 ** idx qc.x(q_controls[idx]) qc.mcry(theta, q_controls, q_target[0], q_ancillas, mode='basic', @@ -590,7 +590,7 @@ def test_multi_controlled_y_rotation_matrix_basic_mode(self, num_controls, use_b backend = BasicAer.get_backend('unitary_simulator') mat_mcu = execute(qc, backend).result().get_unitary(qc) - dim = 2**(num_controls + 1) + dim = 2 ** (num_controls + 1) mat_mcu = mat_mcu[:dim, :dim] pos = dim - 2 * (control_int + 1) mat_groundtruth = np.eye(dim, dtype=complex) @@ -741,12 +741,12 @@ def _compute_control_matrix(base_mat, num_ctrl_qubits): ndarray: controlled version of base matrix. """ num_target = int(np.log2(base_mat.shape[0])) - ctrl_dim = 2**num_ctrl_qubits + ctrl_dim = 2 ** num_ctrl_qubits ctrl_grnd = np.repeat([[1], [0]], [1, ctrl_dim - 1]) full_mat_dim = ctrl_dim * base_mat.shape[0] full_mat = np.zeros((full_mat_dim, full_mat_dim), dtype=base_mat.dtype) ctrl_proj = np.diag(np.roll(ctrl_grnd, ctrl_dim - 1)) - full_mat = (np.kron(np.eye(2**num_target), + full_mat = (np.kron(np.eye(2 ** num_target), np.eye(ctrl_dim) - ctrl_proj) + np.kron(base_mat, ctrl_proj)) return full_mat From 7807ac1bf225eb70bc454327a9ba578d4d30473e Mon Sep 17 00:00:00 2001 From: Luciano Bello Date: Thu, 23 Jan 2020 13:04:54 -0300 Subject: [PATCH 13/20] unify style --- test/python/circuit/test_controlled_gate.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/test/python/circuit/test_controlled_gate.py b/test/python/circuit/test_controlled_gate.py index 0df25ac38355..6dadd0517dc2 100644 --- a/test/python/circuit/test_controlled_gate.py +++ b/test/python/circuit/test_controlled_gate.py @@ -341,9 +341,11 @@ def test_multi_control_toffoli_matrix_clean_ancillas(self, num_controls): qc = QuantumCircuit(q_target, q_controls) # add ancillas if necessary - num_ancillas = 0 if num_controls <= 2 else num_controls - 2 q_ancillas = None - if num_ancillas > 0: + if num_controls <= 2: + num_ancillas = 0 + else: + num_ancillas = num_controls - 2 q_ancillas = QuantumRegister(num_ancillas) qc.add_register(q_ancillas) From 9306bfd649b685d60fcbedc6291a156c717116ac Mon Sep 17 00:00:00 2001 From: Luciano Bello Date: Thu, 23 Jan 2020 13:22:48 -0300 Subject: [PATCH 14/20] import gates via allGates --- test/python/circuit/test_controlled_gate.py | 26 +++++++-------------- 1 file changed, 8 insertions(+), 18 deletions(-) diff --git a/test/python/circuit/test_controlled_gate.py b/test/python/circuit/test_controlled_gate.py index 6dadd0517dc2..a77d959370ee 100644 --- a/test/python/circuit/test_controlled_gate.py +++ b/test/python/circuit/test_controlled_gate.py @@ -172,15 +172,12 @@ def test_single_controlled_composite_gate(self): def test_controlled_u3_matrix(self): """Test the matrix representation of the controlled and controlled-controlled U3 gate.""" - import qiskit.extensions.standard.u3 as u3 - import qiskit.extensions.standard.cu3 as cu3 - num_ctrl = 3 # U3 gate params alpha, beta, gamma = 0.2, 0.3, 0.4 # cnu3 gate - u3gate = u3.U3Gate(alpha, beta, gamma) + u3gate = allGates.U3Gate(alpha, beta, gamma) cnu3 = u3gate.control(num_ctrl) width = cnu3.num_qubits qr = QuantumRegister(width) @@ -199,7 +196,7 @@ def test_controlled_u3_matrix(self): width = 3 qr = QuantumRegister(width) qc_cu3 = QuantumCircuit(qr) - cu3gate = cu3.Cu3Gate(alpha, beta, gamma) + cu3gate = allGates.Cu3Gate(alpha, beta, gamma) c_cu3 = cu3gate.control(1) qc_cu3.append(c_cu3, qr, []) @@ -234,15 +231,12 @@ def test_controlled_u3_matrix(self): def test_controlled_u1_matrix(self): """Test the matrix representation of the controlled and controlled-controlled U1 gate.""" - import qiskit.extensions.standard.u1 as u1 - import qiskit.extensions.standard.cu1 as cu1 - num_ctrl = 3 # U1 gate params theta = 0.2 # cnu1 gate - u1gate = u1.U1Gate(theta) + u1gate = allGates.U1Gate(theta) cnu1 = u1gate.control(num_ctrl) width = cnu1.num_qubits qr = QuantumRegister(width) @@ -261,7 +255,7 @@ def test_controlled_u1_matrix(self): width = 3 qr = QuantumRegister(width) qc_cu1 = QuantumCircuit(qr) - cu1gate = cu1.Cu1Gate(theta) + cu1gate = allGates.Cu1Gate(theta) c_cu1 = cu1gate.control(1) qc_cu1.append(c_cu1, qr, []) @@ -440,19 +434,15 @@ def test_multi_control_toffoli_matrix_noancilla_dirty_ancillas(self, num_control def test_single_controlled_rotation_gates(self): """Test the controlled rotation gates controlled on one qubit.""" - import qiskit.extensions.standard.u1 as u1 - import qiskit.extensions.standard.rx as rx - import qiskit.extensions.standard.ry as ry - import qiskit.extensions.standard.rz as rz num_ctrl = 2 num_target = 1 qreg = QuantumRegister(num_ctrl + num_target) theta = pi - gu1 = u1.U1Gate(theta) - grx = rx.RXGate(theta) - gry = ry.RYGate(theta) - grz = rz.RZGate(theta) + gu1 = allGates.U1Gate(theta) + grx = allGates.RXGate(theta) + gry = allGates.RYGate(theta) + grz = allGates.RZGate(theta) ugu1 = ac._unroll_gate(gu1, ['u1', 'u3', 'cx']) ugrx = ac._unroll_gate(grx, ['u1', 'u3', 'cx']) From a3ea4bf4d1bcde8d214db45cc49a5f78f81d34f7 Mon Sep 17 00:00:00 2001 From: Luciano Bello Date: Thu, 23 Jan 2020 16:54:02 -0300 Subject: [PATCH 15/20] unfold test_all_inverses --- test/python/circuit/test_controlled_gate.py | 51 ++++++++++++--------- 1 file changed, 30 insertions(+), 21 deletions(-) diff --git a/test/python/circuit/test_controlled_gate.py b/test/python/circuit/test_controlled_gate.py index a77d959370ee..26597cd6670c 100644 --- a/test/python/circuit/test_controlled_gate.py +++ b/test/python/circuit/test_controlled_gate.py @@ -661,32 +661,41 @@ def test_base_gate_setting(self): cgate = base_gate.control() self.assertEqual(base_gate.base_gate, cgate.base_gate) - def test_all_inverses(self): + @data(allGates.SwapGate, + allGates.HGate, + allGates.SGate, + allGates.SdgGate, + allGates.TGate, + allGates.TdgGate, + allGates.U1Gate, + allGates.U2Gate, + allGates.U3Gate, + allGates.XGate, + allGates.YGate, + allGates.ZGate, + allGates.RGate, + allGates.RXGate, + allGates.RYGate, + allGates.RZGate, + allGates.RZZGate, + allGates.RXXGate, + allGates.MSGate) + def test_gate_inverses(self, gate_classes): """ Test all gates in standard extensions except those that cannot be controlled or are being deprecated. """ - gate_classes = [cls for name, cls in allGates.__dict__.items() - if isinstance(cls, type)] - for cls in gate_classes: - # only verify basic gates right now, as already controlled ones - # will generate differing definitions - if issubclass(cls, ControlledGate) or cls == allGates.IdGate: - continue - try: - sig = signature(cls) - numargs = len([param for param in sig.parameters.values() - if param.kind == param.POSITIONAL_ONLY or - (param.kind == param.POSITIONAL_OR_KEYWORD and - param.default is param.empty)]) - args = [1] * numargs + sig = signature(gate_classes) + numargs = len([param for param in sig.parameters.values() + if param.kind == param.POSITIONAL_ONLY or + (param.kind == param.POSITIONAL_OR_KEYWORD and + param.default is param.empty)]) + args =[1] * numargs - gate = cls(*args) - self.assertEqual(gate.inverse().control(2), - gate.control(2).inverse()) - except AttributeError: - # skip gates that do not have a control attribute (e.g. barrier) - pass + gate = gate_classes( * args) + self.assertEqual(gate.inverse().control(2), + + gate.control(2).inverse()) @data(1, 2, 3) def test_controlled_standard_gates(self, num_ctrl_qubits): From 98ca625a6223103d1a40048d51f5412dbf76d798 Mon Sep 17 00:00:00 2001 From: Luciano Bello Date: Thu, 23 Jan 2020 18:03:10 -0300 Subject: [PATCH 16/20] unfolding test_multi_control_toffoli_matrix --- test/python/circuit/test_controlled_gate.py | 56 ++++++++++++++------- 1 file changed, 39 insertions(+), 17 deletions(-) diff --git a/test/python/circuit/test_controlled_gate.py b/test/python/circuit/test_controlled_gate.py index 26597cd6670c..a7f25e50f2f3 100644 --- a/test/python/circuit/test_controlled_gate.py +++ b/test/python/circuit/test_controlled_gate.py @@ -325,7 +325,35 @@ def test_multi_controlled_u1_matrix(self, num_controls): [(1 - fac) / 2, (1 + fac) / 2]] assert_allclose(mat_mcu, mat_groundtruth) - @data(1, 2, 3) + @data(1, 2) + def test_multi_control_toffoli_matrix(self, num_controls): + """Test the multi-control Toffoli gate with clean ancillas.""" + + # set up circuit + q_controls = QuantumRegister(num_controls) + q_target = QuantumRegister(1) + qc = QuantumCircuit(q_target, q_controls) + + # apply hadamard on control qubits and toffoli gate + qc.h(q_controls) + qc.mct(q_controls, q_target[0], None, mode='basic') + + # execute the circuit and obtain statevector result + backend = BasicAer.get_backend('statevector_simulator') + vec_mct = execute(qc, backend).result().get_statevector(qc) + + # compare to expectation + mat = np.eye(2 ** (num_controls + 1)) + mat[-2:, -2:] = [[0, 1], [1, 0]] + + vec_groundtruth = mat @ np.kron(np.kron( + np.array([1] + [0] * (2 ** -1)), + [1 / 2 ** (num_controls / 2)] * 2 ** num_controls), [1, 0]) + + s_f = state_fidelity(vec_mct, vec_groundtruth) + self.assertAlmostEqual(s_f, 1) + + @data(3, 4) def test_multi_control_toffoli_matrix_clean_ancillas(self, num_controls): """Test the multi-control Toffoli gate with clean ancillas.""" @@ -334,14 +362,9 @@ def test_multi_control_toffoli_matrix_clean_ancillas(self, num_controls): q_target = QuantumRegister(1) qc = QuantumCircuit(q_target, q_controls) - # add ancillas if necessary - q_ancillas = None - if num_controls <= 2: - num_ancillas = 0 - else: - num_ancillas = num_controls - 2 - q_ancillas = QuantumRegister(num_ancillas) - qc.add_register(q_ancillas) + num_ancillas = num_controls - 2 + q_ancillas = QuantumRegister(num_ancillas) + qc.add_register(q_ancillas) # apply hadamard on control qubits and toffoli gate qc.h(q_controls) @@ -354,8 +377,7 @@ def test_multi_control_toffoli_matrix_clean_ancillas(self, num_controls): # compare to expectation mat = np.eye(2 ** (num_controls + 1)) mat[-2:, -2:] = [[0, 1], [1, 0]] - if num_ancillas > 0: - mat = np.kron(np.eye(2 ** num_ancillas), mat) + mat = np.kron(np.eye(2 ** num_ancillas), mat) vec_groundtruth = mat @ np.kron(np.kron( np.array([1] + [0] * (2 ** num_ancillas - 1)), @@ -687,15 +709,15 @@ def test_gate_inverses(self, gate_classes): """ sig = signature(gate_classes) numargs = len([param for param in sig.parameters.values() - if param.kind == param.POSITIONAL_ONLY or - (param.kind == param.POSITIONAL_OR_KEYWORD and - param.default is param.empty)]) - args =[1] * numargs + if param.kind == param.POSITIONAL_ONLY or + (param.kind == param.POSITIONAL_OR_KEYWORD and + param.default is param.empty)]) + args = [1] * numargs - gate = gate_classes( * args) + gate = gate_classes(*args) self.assertEqual(gate.inverse().control(2), - gate.control(2).inverse()) + gate.control(2).inverse()) @data(1, 2, 3) def test_controlled_standard_gates(self, num_ctrl_qubits): From b4f5182b34c508b5e3ef0045c6a892ecbdbd770d Mon Sep 17 00:00:00 2001 From: Luciano Bello Date: Thu, 23 Jan 2020 18:05:51 -0300 Subject: [PATCH 17/20] simplification --- test/python/circuit/test_controlled_gate.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/python/circuit/test_controlled_gate.py b/test/python/circuit/test_controlled_gate.py index a7f25e50f2f3..010a06b6d610 100644 --- a/test/python/circuit/test_controlled_gate.py +++ b/test/python/circuit/test_controlled_gate.py @@ -347,7 +347,7 @@ def test_multi_control_toffoli_matrix(self, num_controls): mat[-2:, -2:] = [[0, 1], [1, 0]] vec_groundtruth = mat @ np.kron(np.kron( - np.array([1] + [0] * (2 ** -1)), + np.array([1]), [1 / 2 ** (num_controls / 2)] * 2 ** num_controls), [1, 0]) s_f = state_fidelity(vec_mct, vec_groundtruth) From e1ae50871ddfa1dd746117e18441dc76d527fe00 Mon Sep 17 00:00:00 2001 From: Cryoris Date: Wed, 19 Feb 2020 17:54:18 +0100 Subject: [PATCH 18/20] use _compute_control_matrix where possible --- test/python/circuit/test_controlled_gate.py | 219 ++++++++------------ 1 file changed, 83 insertions(+), 136 deletions(-) diff --git a/test/python/circuit/test_controlled_gate.py b/test/python/circuit/test_controlled_gate.py index 9b3bdc947eb3..4310de09833e 100644 --- a/test/python/circuit/test_controlled_gate.py +++ b/test/python/circuit/test_controlled_gate.py @@ -302,101 +302,64 @@ def test_multi_controlled_u1_matrix(self, num_controls): q_target = QuantumRegister(1) # iterate over all possible combinations of control qubits - allsubsets = list(itertools.chain(*[itertools.combinations(range(num_controls), ni) - for ni in range(num_controls + 1)])) - for subset in allsubsets: - control_int = 0 + for ctrl_state in range(2**num_controls): + bitstr = bin(ctrl_state)[2:].zfill(num_controls)[::-1] lam = 0.3165354 * pi - qc = QuantumCircuit(q_target, q_controls) - for idx in subset: - control_int += 2 ** idx - qc.x(q_controls[idx]) + qc = QuantumCircuit(q_controls, q_target) + for idx, bit in enumerate(bitstr): + if bit == '0': + qc.x(q_controls[idx]) - qc.h(q_target[0]) qc.mcu1(lam, q_controls, q_target[0]) - qc.h(q_target[0]) - for idx in subset: - qc.x(q_controls[idx]) + # for idx in subset: + for idx, bit in enumerate(bitstr): + if bit == '0': + qc.x(q_controls[idx]) backend = BasicAer.get_backend('unitary_simulator') - mat_mcu = execute(qc, backend).result().get_unitary(qc) - - dim = 2 ** (num_controls + 1) - pos = dim - 2 * (control_int + 1) - mat_groundtruth = np.eye(dim, dtype=complex) - fac = np.exp(1j * lam) - mat_groundtruth[pos:pos + 2, pos:pos + 2] = [[(1 + fac) / 2, (1 - fac) / 2], - [(1 - fac) / 2, (1 + fac) / 2]] - self.assertTrue(matrix_equal(mat_mcu, mat_groundtruth, ignore_phase=False)) - - @data(1, 2) - def test_multi_control_toffoli_matrix(self, num_controls): - """Test the multi-control Toffoli gate with clean ancillas.""" - - # set up circuit - q_controls = QuantumRegister(num_controls) - q_target = QuantumRegister(1) - qc = QuantumCircuit(q_target, q_controls) + simulated = execute(qc, backend).result().get_unitary(qc) - # apply hadamard on control qubits and toffoli gate - qc.h(q_controls) - qc.mct(q_controls, q_target[0], None, mode='basic') - - # execute the circuit and obtain statevector result - backend = BasicAer.get_backend('statevector_simulator') - vec_mct = execute(qc, backend).result().get_statevector(qc) + base = U1Gate(lam).to_matrix() + expected = _compute_control_matrix(base, num_controls, ctrl_state=ctrl_state) + self.assertTrue(matrix_equal(simulated, expected)) - # compare to expectation - mat = np.eye(2 ** (num_controls + 1)) - mat[-2:, -2:] = [[0, 1], [1, 0]] - - vec_groundtruth = mat @ np.kron(np.kron( - np.array([1]), - [1 / 2 ** (num_controls / 2)] * 2 ** num_controls), [1, 0]) - - s_f = state_fidelity(vec_mct, vec_groundtruth) - self.assertAlmostEqual(s_f, 1) - - @data(3, 4) + @data(1, 2, 3, 4) def test_multi_control_toffoli_matrix_clean_ancillas(self, num_controls): """Test the multi-control Toffoli gate with clean ancillas.""" - # set up circuit q_controls = QuantumRegister(num_controls) q_target = QuantumRegister(1) - qc = QuantumCircuit(q_target, q_controls) + qc = QuantumCircuit(q_controls, q_target) - num_ancillas = num_controls - 2 - q_ancillas = QuantumRegister(num_ancillas) - qc.add_register(q_ancillas) + if num_controls > 2: + num_ancillas = num_controls - 2 + q_ancillas = QuantumRegister(num_controls) + qc.add_register(q_ancillas) + else: + num_ancillas = 0 # apply hadamard on control qubits and toffoli gate - qc.h(q_controls) - qc.mct(q_controls, q_target[0], q_ancillas, mode='basic') + qc.mct(q_controls, q_target[0], None, mode='basic') # execute the circuit and obtain statevector result - backend = BasicAer.get_backend('statevector_simulator') - vec_mct = execute(qc, backend).result().get_statevector(qc) + backend = BasicAer.get_backend('unitary_simulator') + simulated = execute(qc, backend).result().get_unitary(qc) # compare to expectation - mat = np.eye(2 ** (num_controls + 1)) - mat[-2:, -2:] = [[0, 1], [1, 0]] - mat = np.kron(np.eye(2 ** num_ancillas), mat) - - vec_groundtruth = mat @ np.kron(np.kron( - np.array([1] + [0] * (2 ** num_ancillas - 1)), - [1 / 2 ** (num_controls / 2)] * 2 ** num_controls), [1, 0]) + if num_ancillas > 0: + simulated = simulated[:2**(num_controls + 1), :2**(num_controls + 1)] - s_f = state_fidelity(vec_mct, vec_groundtruth) - self.assertAlmostEqual(s_f, 1) + base = XGate().to_matrix() + expected = _compute_control_matrix(base, num_controls) + self.assertTrue(matrix_equal(simulated, expected)) @data(1, 2, 3, 4, 5) def test_multi_control_toffoli_matrix_basic_dirty_ancillas(self, num_controls): """Test the multi-control Toffoli gate with dirty ancillas (basic-dirty-ancilla).""" q_controls = QuantumRegister(num_controls) q_target = QuantumRegister(1) - qc = QuantumCircuit(q_target, q_controls) + qc = QuantumCircuit(q_controls, q_target) q_ancillas = None if num_controls <= 2: @@ -408,21 +371,20 @@ def test_multi_control_toffoli_matrix_basic_dirty_ancillas(self, num_controls): qc.mct(q_controls, q_target[0], q_ancillas, mode='basic-dirty-ancilla') - mat_mct = execute(qc, BasicAer.get_backend('unitary_simulator')).result().get_unitary(qc) - - mat_groundtruth = np.eye(2 ** (num_controls + 1)) - mat_groundtruth[-2:, -2:] = [[0, 1], [1, 0]] + simulated = execute(qc, BasicAer.get_backend('unitary_simulator')).result().get_unitary(qc) if num_ancillas > 0: - mat_groundtruth = np.kron(np.eye(2 ** num_ancillas), mat_groundtruth) + simulated = simulated[:2**(num_controls + 1), :2**(num_controls + 1)] - self.assertTrue(matrix_equal(mat_mct, mat_groundtruth, ignore_phase=False, atol=1e-8)) + base = XGate().to_matrix() + expected = _compute_control_matrix(base, num_controls) + self.assertTrue(matrix_equal(simulated, expected, atol=1e-8)) @data(1, 2, 3, 4, 5) def test_multi_control_toffoli_matrix_advanced_dirty_ancillas(self, num_controls): """Test the multi-control Toffoli gate with dirty ancillas (advanced).""" q_controls = QuantumRegister(num_controls) q_target = QuantumRegister(1) - qc = QuantumCircuit(q_target, q_controls) + qc = QuantumCircuit(q_controls, q_target) q_ancillas = None if num_controls <= 4: @@ -434,30 +396,28 @@ def test_multi_control_toffoli_matrix_advanced_dirty_ancillas(self, num_controls qc.mct(q_controls, q_target[0], q_ancillas, mode='advanced') - mat_mct = execute(qc, BasicAer.get_backend('unitary_simulator')).result().get_unitary(qc) - - mat_groundtruth = np.eye(2 ** (num_controls + 1)) - mat_groundtruth[-2:, -2:] = [[0, 1], [1, 0]] + simulated = execute(qc, BasicAer.get_backend('unitary_simulator')).result().get_unitary(qc) if num_ancillas > 0: - mat_groundtruth = np.kron(np.eye(2 ** num_ancillas), mat_groundtruth) + simulated = simulated[:2**(num_controls + 1), :2**(num_controls + 1)] - self.assertTrue(matrix_equal(mat_mct, mat_groundtruth, atol=1e-8, ignore_phase=False)) + base = XGate().to_matrix() + expected = _compute_control_matrix(base, num_controls) + self.assertTrue(matrix_equal(simulated, expected, atol=1e-8)) - @data(1, 2, 3, 4, 5) + @data(1, 2, 3) def test_multi_control_toffoli_matrix_noancilla_dirty_ancillas(self, num_controls): """Test the multi-control Toffoli gate with dirty ancillas (noancilla).""" q_controls = QuantumRegister(num_controls) q_target = QuantumRegister(1) - qc = QuantumCircuit(q_target, q_controls) + qc = QuantumCircuit(q_controls, q_target) qc.mct(q_controls, q_target[0], None, mode='noancilla') - mat_mct = execute(qc, BasicAer.get_backend('unitary_simulator')).result().get_unitary(qc) + simulated = execute(qc, BasicAer.get_backend('unitary_simulator')).result().get_unitary(qc) - mat_groundtruth = np.eye(2 ** (num_controls + 1)) - mat_groundtruth[-2:, -2:] = [[0, 1], [1, 0]] - - self.assertTrue(matrix_equal(mat_mct, mat_groundtruth, atol=1e-8, ignore_phase=False)) + base = XGate().to_matrix() + expected = _compute_control_matrix(base, num_controls) + self.assertTrue(matrix_equal(simulated, expected, atol=1e-8)) def test_single_controlled_rotation_gates(self): """Test the controlled rotation gates controlled on one qubit.""" @@ -533,15 +493,15 @@ def test_multi_controlled_rotation_gate_matrices(self, num_controls, base_gate_n """Test the multi controlled rotation gates without ancillas.""" q_controls = QuantumRegister(num_controls) q_target = QuantumRegister(1) - allsubsets = list(itertools.chain(*[itertools.combinations(range(num_controls), ni) for - ni in range(num_controls + 1)])) - for subset in allsubsets: - control_int = 0 + + # iterate over all possible combinations of control qubits + for ctrl_state in range(2**num_controls): + bitstr = bin(ctrl_state)[2:].zfill(num_controls)[::-1] theta = 0.871236 * pi - qc = QuantumCircuit(q_target, q_controls) - for idx in subset: - control_int += 2 ** idx - qc.x(q_controls[idx]) + qc = QuantumCircuit(q_controls, q_target) + for idx, bit in enumerate(bitstr): + if bit == '0': + qc.x(q_controls[idx]) # call mcrx/mcry/mcrz if base_gate_name == 'y': @@ -551,31 +511,22 @@ def test_multi_controlled_rotation_gate_matrices(self, num_controls, base_gate_n getattr(qc, 'mcr' + base_gate_name)(theta, q_controls, q_target[0], use_basis_gates=use_basis_gates) - for idx in subset: - qc.x(q_controls[idx]) + for idx, bit in enumerate(bitstr): + if bit == '0': + qc.x(q_controls[idx]) backend = BasicAer.get_backend('unitary_simulator') - mat_mcu = execute(qc, backend).result().get_unitary(qc) - - dim = 2 ** (num_controls + 1) - pos = dim - 2 * (control_int + 1) - mat_groundtruth = np.eye(dim, dtype=complex) + simulated = execute(qc, backend).result().get_unitary(qc) if base_gate_name == 'x': - rot_mat = np.array([[np.cos(theta / 2), -1j * np.sin(theta / 2)], - [-1j * np.sin(theta / 2), np.cos(theta / 2)]], - dtype=complex) + rot_mat = RXGate(theta).to_matrix() elif base_gate_name == 'y': - rot_mat = np.array([[np.cos(theta / 2), -np.sin(theta / 2)], - [np.sin(theta / 2), np.cos(theta / 2)]], - dtype=complex) + rot_mat = RYGate(theta).to_matrix() else: # case 'z' - rot_mat = np.array([[1, 0], - [0, np.exp(1j * theta)]], - dtype=complex) + rot_mat = U1Gate(theta).to_matrix() - mat_groundtruth[pos:pos + 2, pos:pos + 2] = rot_mat - self.assertTrue(matrix_equal(mat_mcu, mat_groundtruth, ignore_phase=False)) + expected = _compute_control_matrix(rot_mat, num_controls, ctrl_state=ctrl_state) + self.assertTrue(matrix_equal(simulated, expected)) @combine(num_controls=[1, 2, 4], use_basis_gates=[True, False]) def test_multi_controlled_y_rotation_matrix_basic_mode(self, num_controls, use_basis_gates): @@ -589,42 +540,38 @@ def test_multi_controlled_y_rotation_matrix_basic_mode(self, num_controls, use_b q_controls = QuantumRegister(num_controls) q_target = QuantumRegister(1) - allsubsets = list(itertools.chain(*[itertools.combinations(range(num_controls), ni) for - ni in range(num_controls + 1)])) - for subset in allsubsets: - control_int = 0 + + for ctrl_state in range(2**num_controls): + bitstr = bin(ctrl_state)[2:].zfill(num_controls)[::-1] theta = 0.871236 * pi - qc = QuantumCircuit(q_target, q_controls) if num_ancillas > 0: q_ancillas = QuantumRegister(num_ancillas) - qc.add_register(q_ancillas) + qc = QuantumCircuit(q_controls, q_target, q_ancillas) else: + qc = QuantumCircuit(q_controls, q_target) q_ancillas = None - for idx in subset: - control_int += 2 ** idx - qc.x(q_controls[idx]) + for idx, bit in enumerate(bitstr): + if bit == '0': + qc.x(q_controls[idx]) qc.mcry(theta, q_controls, q_target[0], q_ancillas, mode='basic', use_basis_gates=use_basis_gates) - for idx in subset: - qc.x(q_controls[idx]) + for idx, bit in enumerate(bitstr): + if bit == '0': + qc.x(q_controls[idx]) - backend = BasicAer.get_backend('unitary_simulator') - mat_mcu = execute(qc, backend).result().get_unitary(qc) + rot_mat = RYGate(theta).to_matrix() - dim = 2 ** (num_controls + 1) - mat_mcu = mat_mcu[:dim, :dim] - pos = dim - 2 * (control_int + 1) - mat_groundtruth = np.eye(dim, dtype=complex) + backend = BasicAer.get_backend('unitary_simulator') + simulated = execute(qc, backend).result().get_unitary(qc) + if num_ancillas > 0: + simulated = simulated[:2**(num_controls + 1), :2**(num_controls+1)] - rot_mat = np.array([[np.cos(theta / 2), -np.sin(theta / 2)], - [np.sin(theta / 2), np.cos(theta / 2)]], - dtype=complex) + expected = _compute_control_matrix(rot_mat, num_controls, ctrl_state=ctrl_state) - mat_groundtruth[pos:pos + 2, pos:pos + 2] = rot_mat - self.assertTrue(matrix_equal(mat_mcu, mat_groundtruth, ignore_phase=False)) + self.assertTrue(matrix_equal(simulated, expected)) @data(1, 2, 3, 4) def test_inverse_x(self, num_ctrl_qubits): From 022f53b1d2184800b916857df85b7b7f6d8077d4 Mon Sep 17 00:00:00 2001 From: Cryoris Date: Wed, 19 Feb 2020 18:08:51 +0100 Subject: [PATCH 19/20] fix lint --- test/python/circuit/test_controlled_gate.py | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/test/python/circuit/test_controlled_gate.py b/test/python/circuit/test_controlled_gate.py index 4310de09833e..f666cab172ff 100644 --- a/test/python/circuit/test_controlled_gate.py +++ b/test/python/circuit/test_controlled_gate.py @@ -16,7 +16,6 @@ """Test Qiskit's inverse gate operation.""" import unittest -import itertools from inspect import signature from test import combine import numpy as np @@ -27,7 +26,6 @@ from qiskit.test import QiskitTestCase from qiskit.circuit import ControlledGate from qiskit.circuit.exceptions import CircuitError -from qiskit.quantum_info import state_fidelity from qiskit.quantum_info.operators.predicates import matrix_equal, is_unitary_matrix from qiskit.quantum_info.random import random_unitary from qiskit.quantum_info.states import Statevector @@ -636,7 +634,7 @@ def test_open_controlled_unitary_matrix(self, num_ctrl_qubits): target_op = Operator(XGate()) for i in range(num_target_qubits - 1): target_op = target_op.tensor(XGate()) - print('') + for i in range(2**num_qubits): input_bitstring = bin(i)[2:].zfill(num_qubits) input_target = input_bitstring[0:num_target_qubits] @@ -661,9 +659,8 @@ def test_open_controlled_unitary_matrix(self, num_ctrl_qubits): (output_ctrl == input_ctrl) and (output_target == cond_output)) else: - self.assertTrue(( - (output_ctrl == input_ctrl) and - (output_target != cond_output)) or + self.assertTrue( + ((output_ctrl == input_ctrl) and (output_target != cond_output)) or output_ctrl != input_ctrl) def test_base_gate_setting(self): From c61908c1893838d86ecd3f32f94e3031b080bf8f Mon Sep 17 00:00:00 2001 From: Cryoris Date: Sat, 22 Feb 2020 17:14:16 +0100 Subject: [PATCH 20/20] use subtest more, add note that tests from Aqua --- test/python/circuit/test_controlled_gate.py | 51 +++++++++++++++++---- 1 file changed, 41 insertions(+), 10 deletions(-) diff --git a/test/python/circuit/test_controlled_gate.py b/test/python/circuit/test_controlled_gate.py index f666cab172ff..9eed94f3218d 100644 --- a/test/python/circuit/test_controlled_gate.py +++ b/test/python/circuit/test_controlled_gate.py @@ -293,7 +293,11 @@ def test_multi_control_u1(self): @data(1, 2, 3, 4) def test_multi_controlled_u1_matrix(self, num_controls): - """Test the matrix representation of the multi-controlled CU1 gate.""" + """Test the matrix representation of the multi-controlled CU1 gate. + + Based on the test moved here from Aqua: + https://github.com/Qiskit/qiskit-aqua/blob/769ca8f/test/aqua/test_mcu1.py + """ # registers for the circuit q_controls = QuantumRegister(num_controls) @@ -320,11 +324,16 @@ def test_multi_controlled_u1_matrix(self, num_controls): base = U1Gate(lam).to_matrix() expected = _compute_control_matrix(base, num_controls, ctrl_state=ctrl_state) - self.assertTrue(matrix_equal(simulated, expected)) + with self.subTest(msg='control state = {}'.format(ctrl_state)): + self.assertTrue(matrix_equal(simulated, expected)) @data(1, 2, 3, 4) def test_multi_control_toffoli_matrix_clean_ancillas(self, num_controls): - """Test the multi-control Toffoli gate with clean ancillas.""" + """Test the multi-control Toffoli gate with clean ancillas. + + Based on the test moved here from Aqua: + https://github.com/Qiskit/qiskit-aqua/blob/769ca8f/test/aqua/test_mct.py + """ # set up circuit q_controls = QuantumRegister(num_controls) q_target = QuantumRegister(1) @@ -354,7 +363,11 @@ def test_multi_control_toffoli_matrix_clean_ancillas(self, num_controls): @data(1, 2, 3, 4, 5) def test_multi_control_toffoli_matrix_basic_dirty_ancillas(self, num_controls): - """Test the multi-control Toffoli gate with dirty ancillas (basic-dirty-ancilla).""" + """Test the multi-control Toffoli gate with dirty ancillas (basic-dirty-ancilla). + + Based on the test moved here from Aqua: + https://github.com/Qiskit/qiskit-aqua/blob/769ca8f/test/aqua/test_mct.py + """ q_controls = QuantumRegister(num_controls) q_target = QuantumRegister(1) qc = QuantumCircuit(q_controls, q_target) @@ -379,7 +392,11 @@ def test_multi_control_toffoli_matrix_basic_dirty_ancillas(self, num_controls): @data(1, 2, 3, 4, 5) def test_multi_control_toffoli_matrix_advanced_dirty_ancillas(self, num_controls): - """Test the multi-control Toffoli gate with dirty ancillas (advanced).""" + """Test the multi-control Toffoli gate with dirty ancillas (advanced). + + Based on the test moved here from Aqua: + https://github.com/Qiskit/qiskit-aqua/blob/769ca8f/test/aqua/test_mct.py + """ q_controls = QuantumRegister(num_controls) q_target = QuantumRegister(1) qc = QuantumCircuit(q_controls, q_target) @@ -404,7 +421,11 @@ def test_multi_control_toffoli_matrix_advanced_dirty_ancillas(self, num_controls @data(1, 2, 3) def test_multi_control_toffoli_matrix_noancilla_dirty_ancillas(self, num_controls): - """Test the multi-control Toffoli gate with dirty ancillas (noancilla).""" + """Test the multi-control Toffoli gate with dirty ancillas (noancilla). + + Based on the test moved here from Aqua: + https://github.com/Qiskit/qiskit-aqua/blob/769ca8f/test/aqua/test_mct.py + """ q_controls = QuantumRegister(num_controls) q_target = QuantumRegister(1) qc = QuantumCircuit(q_controls, q_target) @@ -488,7 +509,11 @@ def test_single_controlled_rotation_gates(self): use_basis_gates=[True, False]) def test_multi_controlled_rotation_gate_matrices(self, num_controls, base_gate_name, use_basis_gates): - """Test the multi controlled rotation gates without ancillas.""" + """Test the multi controlled rotation gates without ancillas. + + Based on the test moved here from Aqua: + https://github.com/Qiskit/qiskit-aqua/blob/769ca8f/test/aqua/test_mcr.py + """ q_controls = QuantumRegister(num_controls) q_target = QuantumRegister(1) @@ -524,11 +549,16 @@ def test_multi_controlled_rotation_gate_matrices(self, num_controls, base_gate_n rot_mat = U1Gate(theta).to_matrix() expected = _compute_control_matrix(rot_mat, num_controls, ctrl_state=ctrl_state) - self.assertTrue(matrix_equal(simulated, expected)) + with self.subTest(msg='control state = {}'.format(ctrl_state)): + self.assertTrue(matrix_equal(simulated, expected)) @combine(num_controls=[1, 2, 4], use_basis_gates=[True, False]) def test_multi_controlled_y_rotation_matrix_basic_mode(self, num_controls, use_basis_gates): - """Test the multi controlled Y rotation using the mode 'basic'.""" + """Test the multi controlled Y rotation using the mode 'basic'. + + Based on the test moved here from Aqua: + https://github.com/Qiskit/qiskit-aqua/blob/769ca8f/test/aqua/test_mcr.py + """ # get the number of required ancilla qubits if num_controls <= 2: @@ -569,7 +599,8 @@ def test_multi_controlled_y_rotation_matrix_basic_mode(self, num_controls, use_b expected = _compute_control_matrix(rot_mat, num_controls, ctrl_state=ctrl_state) - self.assertTrue(matrix_equal(simulated, expected)) + with self.subTest(msg='control state = {}'.format(ctrl_state)): + self.assertTrue(matrix_equal(simulated, expected)) @data(1, 2, 3, 4) def test_inverse_x(self, num_ctrl_qubits):