def test_euler_basis_selection(self): """Verify decomposition uses euler_basis for 1q gates.""" euler_bases = [ ('U3', ['u3']), ('U1X', ['u1', 'rx']), ('RR', ['r']), ('ZYZ', ['rz', 'ry']), ('ZXZ', ['rz', 'rx']), ('XYX', ['rx', 'ry']), ] kak_gates = [ (CXGate(), 'cx'), (CZGate(), 'cz'), (iSwapGate(), 'iswap'), (RXXGate(np.pi / 2), 'rxx'), ] for basis in product(euler_bases, kak_gates): (euler_basis, oneq_gates), (kak_gate, kak_gate_name) = basis with self.subTest(euler_basis=euler_basis, kak_gate=kak_gate): decomposer = TwoQubitBasisDecomposer(kak_gate, euler_basis=euler_basis) unitary = random_unitary(4) self.check_exact_decomposition(unitary.data, decomposer) decomposition_basis = set(decomposer(unitary).count_ops()) requested_basis = set(oneq_gates + [kak_gate_name]) self.assertTrue(decomposition_basis.issubset(requested_basis))
class TestTwoQubitDecomposeExact(CheckDecompositions): """Test TwoQubitBasisDecomposer() for exact decompositions """ def test_cnot_rxx_decompose(self): """Verify CNOT decomposition into RXX gate is correct""" cnot = Operator(CXGate()) decomps = [cnot_rxx_decompose(), cnot_rxx_decompose(plus_ry=True, plus_rxx=True), cnot_rxx_decompose(plus_ry=True, plus_rxx=False), cnot_rxx_decompose(plus_ry=False, plus_rxx=True), cnot_rxx_decompose(plus_ry=False, plus_rxx=False)] for decomp in decomps: self.assertTrue(cnot.equiv(decomp)) @combine(seed=range(10), name='test_exact_two_qubit_cnot_decompose_random_{seed}') def test_exact_two_qubit_cnot_decompose_random(self, seed): """Verify exact CNOT decomposition for random Haar 4x4 unitary (seed={seed}). """ unitary = random_unitary(4, seed=seed) self.check_exact_decomposition(unitary.data, two_qubit_cnot_decompose) def test_exact_two_qubit_cnot_decompose_paulis(self): """Verify exact CNOT decomposition for Paulis """ unitary = Operator.from_label('XZ') self.check_exact_decomposition(unitary.data, two_qubit_cnot_decompose) @combine(seed=range(10), name='test_exact_supercontrolled_decompose_random_{seed}') def test_exact_supercontrolled_decompose_random(self, seed): """Exact decomposition for random supercontrolled basis and random target (seed={seed})""" # pylint: disable=invalid-name k1 = np.kron(random_unitary(2, seed=seed).data, random_unitary(2, seed=seed + 1).data) k2 = np.kron(random_unitary(2, seed=seed + 2).data, random_unitary(2, seed=seed + 3).data) basis_unitary = k1 @ Ud(np.pi / 4, 0, 0) @ k2 decomposer = TwoQubitBasisDecomposer(UnitaryGate(basis_unitary)) self.check_exact_decomposition(random_unitary(4, seed=seed + 4).data, decomposer) def test_exact_nonsupercontrolled_decompose(self): """Check that the nonsupercontrolled basis throws a warning""" with self.assertWarns(UserWarning, msg="Supposed to warn when basis non-supercontrolled"): TwoQubitBasisDecomposer(UnitaryGate(Ud(np.pi / 4, 0.2, 0.1))) def test_cx_equivalence_0cx(self, seed=0): """Check circuits with 0 cx gates locally equivalent to identity """ state = np.random.default_rng(seed) rnd = 2 * np.pi * state.random(size=6) qr = QuantumRegister(2, name='q') qc = QuantumCircuit(qr) qc.u(rnd[0], rnd[1], rnd[2], qr[0]) qc.u(rnd[3], rnd[4], rnd[5], qr[1]) sim = UnitarySimulatorPy() unitary = execute(qc, sim).result().get_unitary() self.assertEqual(two_qubit_cnot_decompose.num_basis_gates(unitary), 0) self.assertTrue(Operator(two_qubit_cnot_decompose(unitary)).equiv(unitary)) def test_cx_equivalence_1cx(self, seed=1): """Check circuits with 1 cx gates locally equivalent to a cx """ state = np.random.default_rng(seed) rnd = 2 * np.pi * state.random(size=12) qr = QuantumRegister(2, name='q') qc = QuantumCircuit(qr) qc.u(rnd[0], rnd[1], rnd[2], qr[0]) qc.u(rnd[3], rnd[4], rnd[5], qr[1]) qc.cx(qr[1], qr[0]) qc.u(rnd[6], rnd[7], rnd[8], qr[0]) qc.u(rnd[9], rnd[10], rnd[11], qr[1]) sim = UnitarySimulatorPy() unitary = execute(qc, sim).result().get_unitary() self.assertEqual(two_qubit_cnot_decompose.num_basis_gates(unitary), 1) self.assertTrue(Operator(two_qubit_cnot_decompose(unitary)).equiv(unitary)) def test_cx_equivalence_2cx(self, seed=2): """Check circuits with 2 cx gates locally equivalent to some circuit with 2 cx. """ state = np.random.default_rng(seed) rnd = 2 * np.pi * state.random(size=18) qr = QuantumRegister(2, name='q') qc = QuantumCircuit(qr) qc.u(rnd[0], rnd[1], rnd[2], qr[0]) qc.u(rnd[3], rnd[4], rnd[5], qr[1]) qc.cx(qr[1], qr[0]) qc.u(rnd[6], rnd[7], rnd[8], qr[0]) qc.u(rnd[9], rnd[10], rnd[11], qr[1]) qc.cx(qr[0], qr[1]) qc.u(rnd[12], rnd[13], rnd[14], qr[0]) qc.u(rnd[15], rnd[16], rnd[17], qr[1]) sim = UnitarySimulatorPy() unitary = execute(qc, sim).result().get_unitary() self.assertEqual(two_qubit_cnot_decompose.num_basis_gates(unitary), 2) self.assertTrue(Operator(two_qubit_cnot_decompose(unitary)).equiv(unitary)) def test_cx_equivalence_3cx(self, seed=3): """Check circuits with 3 cx gates are outside the 0, 1, and 2 qubit regions. """ state = np.random.default_rng(seed) rnd = 2 * np.pi * state.random(size=24) qr = QuantumRegister(2, name='q') qc = QuantumCircuit(qr) qc.u(rnd[0], rnd[1], rnd[2], qr[0]) qc.u(rnd[3], rnd[4], rnd[5], qr[1]) qc.cx(qr[1], qr[0]) qc.u(rnd[6], rnd[7], rnd[8], qr[0]) qc.u(rnd[9], rnd[10], rnd[11], qr[1]) qc.cx(qr[0], qr[1]) qc.u(rnd[12], rnd[13], rnd[14], qr[0]) qc.u(rnd[15], rnd[16], rnd[17], qr[1]) qc.cx(qr[1], qr[0]) qc.u(rnd[18], rnd[19], rnd[20], qr[0]) qc.u(rnd[21], rnd[22], rnd[23], qr[1]) sim = UnitarySimulatorPy() unitary = execute(qc, sim).result().get_unitary() self.assertEqual(two_qubit_cnot_decompose.num_basis_gates(unitary), 3) self.assertTrue(Operator(two_qubit_cnot_decompose(unitary)).equiv(unitary)) def test_seed_289(self): """This specific case failed when PR #3585 was applied See https://github.com/Qiskit/qiskit-terra/pull/3652""" unitary = random_unitary(4, seed=289) self.check_exact_decomposition(unitary.data, two_qubit_cnot_decompose) @combine(seed=range(10), euler_bases=[('U3', ['u3']), ('U', ['u']), ('U1X', ['u1', 'rx']), ('RR', ['r']), ('PSX', ['p', 'sx']), ('ZYZ', ['rz', 'ry']), ('ZXZ', ['rz', 'rx']), ('XYX', ['rx', 'ry']), ('ZSX', ['rz', 'sx'])], kak_gates=[(CXGate(), 'cx'), (CZGate(), 'cz'), (iSwapGate(), 'iswap'), (RXXGate(np.pi / 2), 'rxx')], name='test_euler_basis_selection_{seed}_{euler_bases[0]}_{kak_gates[1]}') def test_euler_basis_selection(self, euler_bases, kak_gates, seed): """Verify decomposition uses euler_basis for 1q gates.""" (euler_basis, oneq_gates) = euler_bases (kak_gate, kak_gate_name) = kak_gates with self.subTest(euler_basis=euler_basis, kak_gate=kak_gate): decomposer = TwoQubitBasisDecomposer(kak_gate, euler_basis=euler_basis) unitary = random_unitary(4, seed=seed) self.check_exact_decomposition(unitary.data, decomposer) decomposition_basis = set(decomposer(unitary).count_ops()) requested_basis = set(oneq_gates + [kak_gate_name]) self.assertTrue( decomposition_basis.issubset(requested_basis))