From 6d35f9efd19796d6332d81bd7f3cdfc0ccf23d8c Mon Sep 17 00:00:00 2001 From: Luciano Bello Date: Tue, 10 Dec 2019 02:50:55 +0200 Subject: [PATCH 01/49] a deterministic test_synthesis.py --- test/python/quantum_info/test_synthesis.py | 100 ++++++++------------- 1 file changed, 37 insertions(+), 63 deletions(-) diff --git a/test/python/quantum_info/test_synthesis.py b/test/python/quantum_info/test_synthesis.py index 4ee8122502d9..7bc78f90b3fd 100644 --- a/test/python/quantum_info/test_synthesis.py +++ b/test/python/quantum_info/test_synthesis.py @@ -105,7 +105,7 @@ def test_euler_angles_1q_random(self, nsamples=100): """Verify euler_angles_1q produces correct Euler angles for random unitaries. """ for _ in range(nsamples): - unitary = random_unitary(2) + unitary = random_unitary(2, seed=442) self.check_one_qubit_euler_angles(unitary) @@ -174,25 +174,25 @@ def test_one_qubit_hard_thetas_xyx_basis(self): def test_one_qubit_random_u3_basis(self, nsamples=50): """Verify for u3 basis and random unitaries.""" for _ in range(nsamples): - unitary = random_unitary(2) + unitary = random_unitary(2, seed=1) self.check_one_qubit_euler_angles(unitary, 'U3') def test_one_qubit_random_u1x_basis(self, nsamples=50): """Verify for u1, x90 basis and random unitaries.""" for _ in range(nsamples): - unitary = random_unitary(2) + unitary = random_unitary(2, seed=2) self.check_one_qubit_euler_angles(unitary, 'U1X') def test_one_qubit_random_zyz_basis(self, nsamples=50): """Verify for rz, ry, rz basis and random unitaries.""" for _ in range(nsamples): - unitary = random_unitary(2) + unitary = random_unitary(2, seed=4) self.check_one_qubit_euler_angles(unitary, 'ZYZ') def test_one_qubit_random_xyx_basis(self, nsamples=50): """Verify for rx, ry, rx basis and random unitaries.""" for _ in range(nsamples): - unitary = random_unitary(2) + unitary = random_unitary(2, seed=5) self.check_one_qubit_euler_angles(unitary, 'XYX') @@ -393,7 +393,7 @@ def test_exact_two_qubit_cnot_decompose_random(self, nsamples=10): """Verify exact CNOT decomposition for random Haar 4x4 unitaries. """ for _ in range(nsamples): - unitary = random_unitary(4) + unitary = random_unitary(4, seed=42) self.check_exact_decomposition(unitary.data, two_qubit_cnot_decompose) def test_exact_two_qubit_cnot_decompose_paulis(self): @@ -407,120 +407,94 @@ def test_exact_supercontrolled_decompose_random(self, nsamples=10): """Verify exact decomposition for random supercontrolled basis and random target""" for _ in range(nsamples): - k1 = np.kron(random_unitary(2).data, random_unitary(2).data) - k2 = np.kron(random_unitary(2).data, random_unitary(2).data) + k1 = np.kron(random_unitary(2, seed=42).data, random_unitary(2, seed=44).data) + k2 = np.kron(random_unitary(2, seed=43).data, random_unitary(2, seed=45).data) basis_unitary = k1 @ Ud(np.pi/4, 0, 0) @ k2 decomposer = TwoQubitBasisDecomposer(UnitaryGate(basis_unitary)) - self.check_exact_decomposition(random_unitary(4).data, decomposer) + self.check_exact_decomposition(random_unitary(4, seed=50).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_random(self): - """Check random circuits with 0 cx - gates locally eqivilent to identity + def test_cx_equivalence_0cx(self): + """Check circuits with 0 cx gates locally equivalent to identity """ qr = QuantumRegister(2, name='q') qc = QuantumCircuit(qr) - rnd = 2*np.pi*np.random.random(size=3) - qc.u3(rnd[0], rnd[1], rnd[2], qr[0]) - rnd = 2*np.pi*np.random.random(size=3) - qc.u3(rnd[0], rnd[1], rnd[2], qr[1]) + qc.u3(5.93716757, 5.12060183, 1.77882926, qr[0]) # generated w/ 2*np.pi*random(size=3) + qc.u3(3.07225205, 2.47163021, 1.85387544, qr[1]) # generated w/ 2*np.pi*random(size=3) sim = UnitarySimulatorPy() U = execute(qc, sim).result().get_unitary() self.assertEqual(two_qubit_cnot_decompose.num_basis_gates(U), 0) - def test_cx_equivalence_1cx_random(self): - """Check random circuits with 1 cx - gates locally eqivilent to a cx + def test_cx_equivalence_1cx(self): + """Check circuits with 1 cx gates locally equivalent to a cx """ qr = QuantumRegister(2, name='q') qc = QuantumCircuit(qr) - rnd = 2*np.pi*np.random.random(size=3) - qc.u3(rnd[0], rnd[1], rnd[2], qr[0]) - rnd = 2*np.pi*np.random.random(size=3) - qc.u3(rnd[0], rnd[1], rnd[2], qr[1]) + qc.u3(5.93716757, 5.12060183, 1.77882926, qr[0]) # generated w/ 2*np.pi*random(size=3) + qc.u3(3.07225205, 2.47163021, 1.85387544, qr[1]) # generated w/ 2*np.pi*random(size=3) qc.cx(qr[1], qr[0]) - rnd = 2*np.pi*np.random.random(size=3) - qc.u3(rnd[0], rnd[1], rnd[2], qr[0]) - rnd = 2*np.pi*np.random.random(size=3) - qc.u3(rnd[0], rnd[1], rnd[2], qr[1]) + qc.u3(2.33171121, 4.71902488, 4.86059273, qr[0]) # generated w/ 2*np.pi*random(size=3) + qc.u3(4.27362122, 1.32003729, 4.84325493, qr[1]) # generated w/ 2*np.pi*random(size=3) sim = UnitarySimulatorPy() U = execute(qc, sim).result().get_unitary() self.assertEqual(two_qubit_cnot_decompose.num_basis_gates(U), 1) - def test_cx_equivalence_2cx_random(self): - """Check random circuits with 2 cx - gates locally eqivilent to some - circuit with 2 cx. + def test_cx_equivalence_2cx(self): + """Check circuits with 2 cx gates locally equivalent to some circuit with 2 cx. """ qr = QuantumRegister(2, name='q') qc = QuantumCircuit(qr) - rnd = 2*np.pi*np.random.random(size=3) - qc.u3(rnd[0], rnd[1], rnd[2], qr[0]) - rnd = 2*np.pi*np.random.random(size=3) - qc.u3(rnd[0], rnd[1], rnd[2], qr[1]) + qc.u3(5.93716757, 5.12060183, 1.77882926, qr[0]) # generated w/ 2*np.pi*random(size=3) + qc.u3(3.07225205, 2.47163021, 1.85387544, qr[1]) # generated w/ 2*np.pi*random(size=3) qc.cx(qr[1], qr[0]) - rnd = 2*np.pi*np.random.random(size=3) - qc.u3(rnd[0], rnd[1], rnd[2], qr[0]) - rnd = 2*np.pi*np.random.random(size=3) - qc.u3(rnd[0], rnd[1], rnd[2], qr[1]) + qc.u3(2.33171121, 4.71902488, 4.86059273, qr[0]) # generated w/ 2*np.pi*random(size=3) + qc.u3(4.27362122, 1.32003729, 4.84325493, qr[1]) # generated w/ 2*np.pi*random(size=3) qc.cx(qr[0], qr[1]) - rnd = 2*np.pi*np.random.random(size=3) - qc.u3(rnd[0], rnd[1], rnd[2], qr[0]) - rnd = 2*np.pi*np.random.random(size=3) - qc.u3(rnd[0], rnd[1], rnd[2], qr[1]) + qc.u3(5.33187487, 3.67914857, 1.51437625, qr[0]) # generated w/ 2*np.pi*random(size=3) + qc.u3(5.95780296, 6.13512175, 5.66765116, qr[1]) # generated w/ 2*np.pi*random(size=3) sim = UnitarySimulatorPy() U = execute(qc, sim).result().get_unitary() self.assertEqual(two_qubit_cnot_decompose.num_basis_gates(U), 2) - def test_cx_equivalence_3cx_random(self): - """Check random circuits with 3 cx - gates are outside the 0, 1, and 2 - qubit regions. + def test_cx_equivalence_3cx(self): + """Check circuits with 3 cx gates are outside the 0, 1, and 2 qubit regions. """ qr = QuantumRegister(2, name='q') qc = QuantumCircuit(qr) - rnd = 2*np.pi*np.random.random(size=3) - qc.u3(rnd[0], rnd[1], rnd[2], qr[0]) - rnd = 2*np.pi*np.random.random(size=3) - qc.u3(rnd[0], rnd[1], rnd[2], qr[1]) + qc.u3(5.93716757, 5.12060183, 1.77882926, qr[0]) # generated w/ 2*np.pi*random(size=3) + qc.u3(3.07225205, 2.47163021, 1.85387544, qr[1]) # generated w/ 2*np.pi*random(size=3) qc.cx(qr[1], qr[0]) - rnd = 2*np.pi*np.random.random(size=3) - qc.u3(rnd[0], rnd[1], rnd[2], qr[0]) - rnd = 2*np.pi*np.random.random(size=3) - qc.u3(rnd[0], rnd[1], rnd[2], qr[1]) + qc.u3(2.33171121, 4.71902488, 4.86059273, qr[0]) # generated w/ 2*np.pi*random(size=3) + qc.u3(4.27362122, 1.32003729, 4.84325493, qr[1]) # generated w/ 2*np.pi*random(size=3) qc.cx(qr[0], qr[1]) - rnd = 2*np.pi*np.random.random(size=3) - qc.u3(rnd[0], rnd[1], rnd[2], qr[0]) - rnd = 2*np.pi*np.random.random(size=3) - qc.u3(rnd[0], rnd[1], rnd[2], qr[1]) + qc.u3(5.33187487, 3.67914857, 1.51437625, qr[0]) # generated w/ 2*np.pi*random(size=3) + qc.u3(5.95780296, 6.13512175, 5.66765116, qr[1]) # generated w/ 2*np.pi*random(size=3) qc.cx(qr[1], qr[0]) - rnd = 2*np.pi*np.random.random(size=3) - qc.u3(rnd[0], rnd[1], rnd[2], qr[0]) - rnd = 2*np.pi*np.random.random(size=3) - qc.u3(rnd[0], rnd[1], rnd[2], qr[1]) + qc.u3(4.77964448, 4.71461107, 0.60003097, qr[0]) # generated w/ 2*np.pi*random(size=3) + qc.u3(4.92087635, 6.08781048, 4.85942885, qr[1]) # generated w/ 2*np.pi*random(size=3) sim = UnitarySimulatorPy() U = execute(qc, sim).result().get_unitary() From 052cbbcdcc54c2538aae45602195043192a7bd80 Mon Sep 17 00:00:00 2001 From: Luciano Bello Date: Sat, 14 Dec 2019 21:02:01 +0200 Subject: [PATCH 02/49] remove loops --- test/python/quantum_info/test_synthesis.py | 93 ++++++++++------------ 1 file changed, 43 insertions(+), 50 deletions(-) diff --git a/test/python/quantum_info/test_synthesis.py b/test/python/quantum_info/test_synthesis.py index 09ab93173be1..970c2fd58a48 100644 --- a/test/python/quantum_info/test_synthesis.py +++ b/test/python/quantum_info/test_synthesis.py @@ -66,7 +66,6 @@ def make_hard_thetas_oneq(smallest=1e-18, factor=3.2, steps=22, phi=0.7, lam=0.9 HARD_THETA_ONEQS = make_hard_thetas_oneq() - # It's too slow to use all 24**4 Clifford combos. If we can make it faster, use a larger set K1K2S = [(ONEQ_CLIFFORDS[3], ONEQ_CLIFFORDS[5], ONEQ_CLIFFORDS[2], ONEQ_CLIFFORDS[21]), (ONEQ_CLIFFORDS[5], ONEQ_CLIFFORDS[6], ONEQ_CLIFFORDS[9], ONEQ_CLIFFORDS[7]), @@ -101,12 +100,11 @@ def test_euler_angles_1q_hard_thetas(self): for gate in HARD_THETA_ONEQS: self.check_one_qubit_euler_angles(Operator(gate)) - def test_euler_angles_1q_random(self, nsamples=100): - """Verify euler_angles_1q produces correct Euler angles for random unitaries. + def test_euler_angles_1q_random(self): + """Verify euler_angles_1q produces correct Euler angles for random_unitary. """ - for _ in range(nsamples): - unitary = random_unitary(2, seed=442) - self.check_one_qubit_euler_angles(unitary) + unitary = random_unitary(2, seed=442) + self.check_one_qubit_euler_angles(unitary) class TestOneQubitEulerDecomposer(QiskitTestCase): @@ -181,41 +179,37 @@ def test_one_qubit_hard_thetas_xyx_basis(self): for gate in HARD_THETA_ONEQS: self.check_one_qubit_euler_angles(Operator(gate), 'XYX') - def test_one_qubit_random_u3_basis(self, nsamples=50): - """Verify for u3 basis and random unitaries.""" - for _ in range(nsamples): - unitary = random_unitary(2, seed=1) - self.check_one_qubit_euler_angles(unitary, 'U3') - - def test_one_qubit_random_u1x_basis(self, nsamples=50): - """Verify for u1, x90 basis and random unitaries.""" - for _ in range(nsamples): - unitary = random_unitary(2, seed=2) - self.check_one_qubit_euler_angles(unitary, 'U1X') - - def test_one_qubit_random_zyz_basis(self, nsamples=50): - """Verify for rz, ry, rz basis and random unitaries.""" - for _ in range(nsamples): - unitary = random_unitary(2, seed=4) - self.check_one_qubit_euler_angles(unitary, 'ZYZ') - - def test_one_qubit_random_zxz_basis(self, nsamples=50): - """Verify for rz, rx, rz basis and random unitaries.""" - for _ in range(nsamples): - unitary = random_unitary(2) - self.check_one_qubit_euler_angles(unitary, 'ZXZ') - - def test_one_qubit_random_xyx_basis(self, nsamples=50): - """Verify for rx, ry, rx basis and random unitaries.""" - for _ in range(nsamples): - unitary = random_unitary(2, seed=5) - self.check_one_qubit_euler_angles(unitary, 'XYX') + def test_one_qubit_random_u3_basis(self): + """Verify for u3 basis and random_unitary.""" + unitary = random_unitary(2, seed=1) + self.check_one_qubit_euler_angles(unitary, 'U3') + + def test_one_qubit_random_u1x_basis(self): + """Verify for u1, x90 basis and random_unitary.""" + unitary = random_unitary(2, seed=2) + self.check_one_qubit_euler_angles(unitary, 'U1X') + + def test_one_qubit_random_zyz_basis(self): + """Verify for rz, ry, rz basis and random_unitary.""" + unitary = random_unitary(2, seed=4) + self.check_one_qubit_euler_angles(unitary, 'ZYZ') + + def test_one_qubit_random_zxz_basis(self): + """Verify for rz, rx, rz basis and random_unitary.""" + unitary = random_unitary(2, seed=5) + self.check_one_qubit_euler_angles(unitary, 'ZXZ') + + def test_one_qubit_random_xyx_basis(self): + """Verify for rx, ry, rx basis and random_unitary.""" + unitary = random_unitary(2, seed=6) + self.check_one_qubit_euler_angles(unitary, 'XYX') # FIXME: streamline the set of test cases class TestTwoQubitWeylDecomposition(QiskitTestCase): """Test TwoQubitWeylDecomposition() """ + # pylint: disable=invalid-name # FIXME: should be possible to set this tolerance tighter after improving the function def check_two_qubit_weyl_decomposition(self, target_unitary, tolerance=1.e-7): @@ -244,7 +238,7 @@ def test_two_qubit_weyl_decomposition_cnot(self): for k1l, k1r, k2l, k2r in K1K2S: k1 = np.kron(k1l.data, k1r.data) k2 = np.kron(k2l.data, k2r.data) - a = Ud(np.pi/4, 0, 0) + a = Ud(np.pi / 4, 0, 0) self.check_two_qubit_weyl_decomposition(k1 @ a @ k2) def test_two_qubit_weyl_decomposition_iswap(self): @@ -252,7 +246,7 @@ def test_two_qubit_weyl_decomposition_iswap(self): for k1l, k1r, k2l, k2r in K1K2S: k1 = np.kron(k1l.data, k1r.data) k2 = np.kron(k2l.data, k2r.data) - a = Ud(np.pi/4, np.pi/4, 0) + a = Ud(np.pi / 4, np.pi / 4, 0) self.check_two_qubit_weyl_decomposition(k1 @ a @ k2) def test_two_qubit_weyl_decomposition_swap(self): @@ -380,6 +374,7 @@ def test_two_qubit_weyl_decomposition_abc(self, smallest=1e-18, factor=9.8, step class TestTwoQubitDecomposeExact(QiskitTestCase): """Test TwoQubitBasisDecomposer() for exact decompositions """ + # pylint: disable=invalid-name def check_exact_decomposition(self, target_unitary, decomposer, tolerance=1.e-7): """Check exact decomposition for a particular target""" @@ -405,12 +400,11 @@ def test_cnot_rxx_decompose(self): for decomp in decomps: self.assertTrue(cnot.equiv(decomp)) - def test_exact_two_qubit_cnot_decompose_random(self, nsamples=10): - """Verify exact CNOT decomposition for random Haar 4x4 unitaries. + def test_exact_two_qubit_cnot_decompose_random(self): + """Verify exact CNOT decomposition for random Haar 4x4 unitary. """ - for _ in range(nsamples): - unitary = random_unitary(4, seed=42) - self.check_exact_decomposition(unitary.data, two_qubit_cnot_decompose) + unitary = random_unitary(4, seed=42) + 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 @@ -419,15 +413,13 @@ def test_exact_two_qubit_cnot_decompose_paulis(self): unitary = Operator(pauli_xz) self.check_exact_decomposition(unitary.data, two_qubit_cnot_decompose) - def test_exact_supercontrolled_decompose_random(self, nsamples=10): + def test_exact_supercontrolled_decompose_random(self): """Verify exact decomposition for random supercontrolled basis and random target""" - - for _ in range(nsamples): - k1 = np.kron(random_unitary(2, seed=42).data, random_unitary(2, seed=44).data) - k2 = np.kron(random_unitary(2, seed=43).data, random_unitary(2, seed=45).data) - basis_unitary = k1 @ Ud(np.pi/4, 0, 0) @ k2 - decomposer = TwoQubitBasisDecomposer(UnitaryGate(basis_unitary)) - self.check_exact_decomposition(random_unitary(4, seed=50).data, decomposer) + k1 = np.kron(random_unitary(2, seed=42).data, random_unitary(2, seed=44).data) + k2 = np.kron(random_unitary(2, seed=43).data, random_unitary(2, seed=45).data) + basis_unitary = k1 @ Ud(np.pi/4, 0, 0) @ k2 + decomposer = TwoQubitBasisDecomposer(UnitaryGate(basis_unitary)) + self.check_exact_decomposition(random_unitary(4, seed=50).data, decomposer) def test_exact_nonsupercontrolled_decompose(self): """Check that the nonsupercontrolled basis throws a warning""" @@ -516,6 +508,7 @@ def test_cx_equivalence_3cx(self): U = execute(qc, sim).result().get_unitary() self.assertEqual(two_qubit_cnot_decompose.num_basis_gates(U), 3) + # FIXME: need to write tests for the approximate decompositions From 2860ac181e8018fc867c5ae9e23757a47636080f Mon Sep 17 00:00:00 2001 From: Luciano Bello Date: Tue, 17 Dec 2019 14:56:54 -0500 Subject: [PATCH 03/49] ddt test_euler_angles_1q_random --- test/python/quantum_info/test_synthesis.py | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/test/python/quantum_info/test_synthesis.py b/test/python/quantum_info/test_synthesis.py index 970c2fd58a48..f7a01dc01a19 100644 --- a/test/python/quantum_info/test_synthesis.py +++ b/test/python/quantum_info/test_synthesis.py @@ -34,6 +34,8 @@ euler_angles_1q) from qiskit.quantum_info.synthesis.ion_decompose import cnot_rxx_decompose from qiskit.test import QiskitTestCase +from test import combine +from ddt import ddt def make_oneq_cliffords(): @@ -74,6 +76,7 @@ def make_hard_thetas_oneq(smallest=1e-18, factor=3.2, steps=22, phi=0.7, lam=0.9 [(0.2, 0.3, 0.1), (0.7, 0.15, 0.22), (0.001, 0.97, 2.2), (3.14, 2.1, 0.9)]]] +@ddt class TestEulerAngles1Q(QiskitTestCase): """Test euler_angles_1q()""" @@ -100,10 +103,14 @@ def test_euler_angles_1q_hard_thetas(self): for gate in HARD_THETA_ONEQS: self.check_one_qubit_euler_angles(Operator(gate)) - def test_euler_angles_1q_random(self): + @combine(seed=range(5), + name='test_euler_angles_1q_random_{seed}', + dsc='Verify euler_angles_1q produces correct ' + 'Euler angles for random_unitary (seed={seed})') + def test_euler_angles_1q_random(self, seed): """Verify euler_angles_1q produces correct Euler angles for random_unitary. """ - unitary = random_unitary(2, seed=442) + unitary = random_unitary(2, seed=seed) self.check_one_qubit_euler_angles(unitary) From 7fa3dceea857a146af5021979a4bb323cb7c96b4 Mon Sep 17 00:00:00 2001 From: Luciano Bello Date: Wed, 18 Dec 2019 11:13:41 -0500 Subject: [PATCH 04/49] test_determinisitc_random_unitary --- test/python/quantum_info/test_random.py | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/test/python/quantum_info/test_random.py b/test/python/quantum_info/test_random.py index aadd15fbaa56..ee39d67b3971 100644 --- a/test/python/quantum_info/test_random.py +++ b/test/python/quantum_info/test_random.py @@ -25,6 +25,19 @@ class TestRandomUtils(QiskitTestCase): """Testing qiskit.quantum_info.random.utils""" + def test_determinisitc_random_unitary(self): + seed = 314159 + unitary = random_unitary(4, seed=seed) + expected = np.array([[0.07749745 + 0.65152329j, 0.40784587 - 0.36593286j, + 0.03129288 + 0.2530866j, 0.36101855 - 0.27184549j], + [0.53016612 - 0.01919937j, 0.48298729 + 0.19460984j, + -0.40381565 - 0.53289147j, -0.00508656 + 0.01841975j], + [-0.32716712 - 0.11010826j, -0.29569725 - 0.11013661j, + -0.23722636 - 0.47383058j, 0.40993924 - 0.57656653j], + [0.04033726 - 0.4089958j, 0.39452908 + 0.4163953j, + 0.37036483 + 0.26451022j, 0.08430501 - 0.53648299j]]) + self.assertTrue(np.allclose(unitary.data, expected)) + def test_unitary(self): """ Test that a random unitary with set seed will not affect later results From 126dacedb99dff2a93d88d95ca08f6f8e3dd438b Mon Sep 17 00:00:00 2001 From: Luciano Bello Date: Wed, 18 Dec 2019 11:23:12 -0500 Subject: [PATCH 05/49] lint --- test/python/quantum_info/test_random.py | 1 + test/python/quantum_info/test_synthesis.py | 4 ++-- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/test/python/quantum_info/test_random.py b/test/python/quantum_info/test_random.py index ee39d67b3971..e221a53766f4 100644 --- a/test/python/quantum_info/test_random.py +++ b/test/python/quantum_info/test_random.py @@ -26,6 +26,7 @@ class TestRandomUtils(QiskitTestCase): """Testing qiskit.quantum_info.random.utils""" def test_determinisitc_random_unitary(self): + """TODO""" seed = 314159 unitary = random_unitary(4, seed=seed) expected = np.array([[0.07749745 + 0.65152329j, 0.40784587 - 0.36593286j, diff --git a/test/python/quantum_info/test_synthesis.py b/test/python/quantum_info/test_synthesis.py index f7a01dc01a19..ec8e9a27618a 100644 --- a/test/python/quantum_info/test_synthesis.py +++ b/test/python/quantum_info/test_synthesis.py @@ -15,6 +15,8 @@ """Tests for quantum synthesis methods.""" import unittest +from test import combine +from ddt import ddt import numpy as np import scipy.linalg as la @@ -34,8 +36,6 @@ euler_angles_1q) from qiskit.quantum_info.synthesis.ion_decompose import cnot_rxx_decompose from qiskit.test import QiskitTestCase -from test import combine -from ddt import ddt def make_oneq_cliffords(): From cb711afafdccd0870a17de3441d58c7824cb2bbf Mon Sep 17 00:00:00 2001 From: Luciano Bello Date: Wed, 18 Dec 2019 13:53:38 -0500 Subject: [PATCH 06/49] docstring --- test/python/quantum_info/test_random.py | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/test/python/quantum_info/test_random.py b/test/python/quantum_info/test_random.py index e221a53766f4..03b7362c647e 100644 --- a/test/python/quantum_info/test_random.py +++ b/test/python/quantum_info/test_random.py @@ -17,6 +17,7 @@ import unittest import numpy as np +from numpy.testing import assert_allclose from qiskit.quantum_info.random import random_unitary, random_density_matrix from qiskit.test import QiskitTestCase @@ -25,8 +26,11 @@ class TestRandomUtils(QiskitTestCase): """Testing qiskit.quantum_info.random.utils""" - def test_determinisitc_random_unitary(self): - """TODO""" + def test_seeded_random_unitary(self): + """Given the same seed, the output should be expected. + Following the numpy approach we are going to try to keep the policy of platform-independent + with randomness. + https://stackoverflow.com/questions/40676205/cross-platform-numpy-random-seed""" seed = 314159 unitary = random_unitary(4, seed=seed) expected = np.array([[0.07749745 + 0.65152329j, 0.40784587 - 0.36593286j, @@ -37,7 +41,7 @@ def test_determinisitc_random_unitary(self): -0.23722636 - 0.47383058j, 0.40993924 - 0.57656653j], [0.04033726 - 0.4089958j, 0.39452908 + 0.4163953j, 0.37036483 + 0.26451022j, 0.08430501 - 0.53648299j]]) - self.assertTrue(np.allclose(unitary.data, expected)) + assert_allclose(unitary.data, expected) def test_unitary(self): """ Test that a random unitary with set seed will not affect later From ce56da0338fed21f8bcd33b041f94633de6d7bf8 Mon Sep 17 00:00:00 2001 From: Luciano Bello Date: Wed, 18 Dec 2019 14:37:33 -0500 Subject: [PATCH 07/49] increase the testing space with ddt --- qiskit/test/utils.py | 2 + test/python/quantum_info/test_synthesis.py | 67 ++++++++++++---------- 2 files changed, 39 insertions(+), 30 deletions(-) diff --git a/qiskit/test/utils.py b/qiskit/test/utils.py index e4ad07faee6d..71cfc304e665 100644 --- a/qiskit/test/utils.py +++ b/qiskit/test/utils.py @@ -108,6 +108,8 @@ def generate_cases(dsc=None, name=None, **kwargs): case = Case(zip(keys, values)) if dsc is not None: setattr(case, "__doc__", dsc.format(**case)) + else: + setattr(case, "__doc__", case.__doc__.format(**case)) if name is not None: setattr(case, "__name__", name.format(**case)) ret.append(case) diff --git a/test/python/quantum_info/test_synthesis.py b/test/python/quantum_info/test_synthesis.py index ec8e9a27618a..b6c14d806b78 100644 --- a/test/python/quantum_info/test_synthesis.py +++ b/test/python/quantum_info/test_synthesis.py @@ -68,6 +68,7 @@ def make_hard_thetas_oneq(smallest=1e-18, factor=3.2, steps=22, phi=0.7, lam=0.9 HARD_THETA_ONEQS = make_hard_thetas_oneq() + # It's too slow to use all 24**4 Clifford combos. If we can make it faster, use a larger set K1K2S = [(ONEQ_CLIFFORDS[3], ONEQ_CLIFFORDS[5], ONEQ_CLIFFORDS[2], ONEQ_CLIFFORDS[21]), (ONEQ_CLIFFORDS[5], ONEQ_CLIFFORDS[6], ONEQ_CLIFFORDS[9], ONEQ_CLIFFORDS[7]), @@ -103,17 +104,15 @@ def test_euler_angles_1q_hard_thetas(self): for gate in HARD_THETA_ONEQS: self.check_one_qubit_euler_angles(Operator(gate)) - @combine(seed=range(5), - name='test_euler_angles_1q_random_{seed}', - dsc='Verify euler_angles_1q produces correct ' - 'Euler angles for random_unitary (seed={seed})') + @combine(seed=range(5), name='test_euler_angles_1q_random_{seed}') def test_euler_angles_1q_random(self, seed): - """Verify euler_angles_1q produces correct Euler angles for random_unitary. + """Verify euler_angles_1q produces correct Euler angles for random_unitary (seed={seed}). """ unitary = random_unitary(2, seed=seed) self.check_one_qubit_euler_angles(unitary) +@ddt class TestOneQubitEulerDecomposer(QiskitTestCase): """Test OneQubitEulerDecomposer""" @@ -186,29 +185,34 @@ def test_one_qubit_hard_thetas_xyx_basis(self): for gate in HARD_THETA_ONEQS: self.check_one_qubit_euler_angles(Operator(gate), 'XYX') - def test_one_qubit_random_u3_basis(self): - """Verify for u3 basis and random_unitary.""" - unitary = random_unitary(2, seed=1) + @combine(seed=range(10), name='test_one_qubit_random_u3_basis_{seed}') + def test_one_qubit_random_u3_basis(self, seed): + """Verify for u3 basis and random_unitary (seed={seed}).""" + unitary = random_unitary(2, seed=seed) self.check_one_qubit_euler_angles(unitary, 'U3') - def test_one_qubit_random_u1x_basis(self): - """Verify for u1, x90 basis and random_unitary.""" - unitary = random_unitary(2, seed=2) + @combine(seed=range(10), name='test_one_qubit_random_u1x_basis_{seed}') + def test_one_qubit_random_u1x_basis(self, seed): + """Verify for u1, x90 basis and random_unitary (seed={seed}).""" + unitary = random_unitary(2, seed=seed) self.check_one_qubit_euler_angles(unitary, 'U1X') - def test_one_qubit_random_zyz_basis(self): - """Verify for rz, ry, rz basis and random_unitary.""" - unitary = random_unitary(2, seed=4) + @combine(seed=range(10), name='test_one_qubit_random_zyz_basis_{seed}') + def test_one_qubit_random_zyz_basis(self, seed): + """Verify for rz, ry, rz basis and random_unitary (seed={seed}).""" + unitary = random_unitary(2, seed=seed) self.check_one_qubit_euler_angles(unitary, 'ZYZ') - def test_one_qubit_random_zxz_basis(self): - """Verify for rz, rx, rz basis and random_unitary.""" - unitary = random_unitary(2, seed=5) + @combine(seed=range(10), name='test_one_qubit_random_zxz_basis_{seed}') + def test_one_qubit_random_zxz_basis(self, seed): + """Verify for rz, rx, rz basis and random_unitary (seed={seed}).""" + unitary = random_unitary(2, seed=seed) self.check_one_qubit_euler_angles(unitary, 'ZXZ') - def test_one_qubit_random_xyx_basis(self): - """Verify for rx, ry, rx basis and random_unitary.""" - unitary = random_unitary(2, seed=6) + @combine(seed=range(10), name='test_one_qubit_random_xyx_basis_{seed}') + def test_one_qubit_random_xyx_basis(self, seed): + """Verify for rx, ry, rx basis and random_unitary (seed={seed}).""" + unitary = random_unitary(2, seed=seed) self.check_one_qubit_euler_angles(unitary, 'XYX') @@ -245,7 +249,7 @@ def test_two_qubit_weyl_decomposition_cnot(self): for k1l, k1r, k2l, k2r in K1K2S: k1 = np.kron(k1l.data, k1r.data) k2 = np.kron(k2l.data, k2r.data) - a = Ud(np.pi / 4, 0, 0) + a = Ud(np.pi/4, 0, 0) self.check_two_qubit_weyl_decomposition(k1 @ a @ k2) def test_two_qubit_weyl_decomposition_iswap(self): @@ -253,7 +257,7 @@ def test_two_qubit_weyl_decomposition_iswap(self): for k1l, k1r, k2l, k2r in K1K2S: k1 = np.kron(k1l.data, k1r.data) k2 = np.kron(k2l.data, k2r.data) - a = Ud(np.pi / 4, np.pi / 4, 0) + a = Ud(np.pi/4, np.pi/4, 0) self.check_two_qubit_weyl_decomposition(k1 @ a @ k2) def test_two_qubit_weyl_decomposition_swap(self): @@ -378,6 +382,7 @@ def test_two_qubit_weyl_decomposition_abc(self, smallest=1e-18, factor=9.8, step self.check_two_qubit_weyl_decomposition(k1 @ a @ k2) +@ddt class TestTwoQubitDecomposeExact(QiskitTestCase): """Test TwoQubitBasisDecomposer() for exact decompositions """ @@ -407,10 +412,11 @@ def test_cnot_rxx_decompose(self): for decomp in decomps: self.assertTrue(cnot.equiv(decomp)) - def test_exact_two_qubit_cnot_decompose_random(self): - """Verify exact CNOT decomposition for random Haar 4x4 unitary. + @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=42) + 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): @@ -420,13 +426,14 @@ def test_exact_two_qubit_cnot_decompose_paulis(self): unitary = Operator(pauli_xz) self.check_exact_decomposition(unitary.data, two_qubit_cnot_decompose) - def test_exact_supercontrolled_decompose_random(self): - """Verify exact decomposition for random supercontrolled basis and random target""" - k1 = np.kron(random_unitary(2, seed=42).data, random_unitary(2, seed=44).data) - k2 = np.kron(random_unitary(2, seed=43).data, random_unitary(2, seed=45).data) + @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})""" + 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=50).data, decomposer) + 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""" From 5799f7554c93b82148ea0f42038eb0988ecdca36 Mon Sep 17 00:00:00 2001 From: Luciano Bello Date: Wed, 18 Dec 2019 14:46:18 -0500 Subject: [PATCH 08/49] clean up --- test/python/quantum_info/test_synthesis.py | 1 - 1 file changed, 1 deletion(-) diff --git a/test/python/quantum_info/test_synthesis.py b/test/python/quantum_info/test_synthesis.py index b6c14d806b78..9e8c7be81636 100644 --- a/test/python/quantum_info/test_synthesis.py +++ b/test/python/quantum_info/test_synthesis.py @@ -522,7 +522,6 @@ def test_cx_equivalence_3cx(self): U = execute(qc, sim).result().get_unitary() self.assertEqual(two_qubit_cnot_decompose.num_basis_gates(U), 3) - # FIXME: need to write tests for the approximate decompositions From c76f9e729cbabe94c40b75fd9f64878788aff9f7 Mon Sep 17 00:00:00 2001 From: Luciano Bello Date: Wed, 18 Dec 2019 14:58:25 -0500 Subject: [PATCH 09/49] tolerance in test_seeded_random_unitary --- test/python/quantum_info/test_random.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/python/quantum_info/test_random.py b/test/python/quantum_info/test_random.py index 03b7362c647e..50664379640c 100644 --- a/test/python/quantum_info/test_random.py +++ b/test/python/quantum_info/test_random.py @@ -41,7 +41,7 @@ def test_seeded_random_unitary(self): -0.23722636 - 0.47383058j, 0.40993924 - 0.57656653j], [0.04033726 - 0.4089958j, 0.39452908 + 0.4163953j, 0.37036483 + 0.26451022j, 0.08430501 - 0.53648299j]]) - assert_allclose(unitary.data, expected) + assert_allclose(unitary.data, expected, atol=1e-8) def test_unitary(self): """ Test that a random unitary with set seed will not affect later From 59affae4279c54e8037d9b765ebf640416578f92 Mon Sep 17 00:00:00 2001 From: Luciano Bello Date: Thu, 19 Dec 2019 11:36:05 -0500 Subject: [PATCH 10/49] moving the checker out --- test/python/quantum_info/test_synthesis.py | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/test/python/quantum_info/test_synthesis.py b/test/python/quantum_info/test_synthesis.py index 9e8c7be81636..4900213d51d8 100644 --- a/test/python/quantum_info/test_synthesis.py +++ b/test/python/quantum_info/test_synthesis.py @@ -77,9 +77,8 @@ def make_hard_thetas_oneq(smallest=1e-18, factor=3.2, steps=22, phi=0.7, lam=0.9 [(0.2, 0.3, 0.1), (0.7, 0.15, 0.22), (0.001, 0.97, 2.2), (3.14, 2.1, 0.9)]]] -@ddt -class TestEulerAngles1Q(QiskitTestCase): - """Test euler_angles_1q()""" +class CheckEulerAngles1Q(QiskitTestCase): + """Implements check_one_qubit_euler_angles()""" def check_one_qubit_euler_angles(self, operator, tolerance=1e-14): """Check euler_angles_1q works for the given unitary""" @@ -94,6 +93,10 @@ def check_one_qubit_euler_angles(self, operator, tolerance=1e-14): maxdist = np.max(np.abs(target_unitary + decomp_unitary)) self.assertTrue(np.abs(maxdist) < tolerance, "Worst distance {}".format(maxdist)) +@ddt +class TestEulerAngles1Q(CheckEulerAngles1Q): + """Test euler_angles_1q()""" + def test_euler_angles_1q_clifford(self): """Verify euler_angles_1q produces correct Euler angles for all Cliffords.""" for clifford in ONEQ_CLIFFORDS: From 82337af9a4890c68a2465eee8a7fbe7b304985d9 Mon Sep 17 00:00:00 2001 From: Luciano Bello Date: Thu, 19 Dec 2019 11:44:24 -0500 Subject: [PATCH 11/49] this self.subTest seems pointless --- test/python/quantum_info/test_synthesis.py | 19 +++++++++---------- 1 file changed, 9 insertions(+), 10 deletions(-) diff --git a/test/python/quantum_info/test_synthesis.py b/test/python/quantum_info/test_synthesis.py index 4900213d51d8..d0eac3fa4df8 100644 --- a/test/python/quantum_info/test_synthesis.py +++ b/test/python/quantum_info/test_synthesis.py @@ -82,16 +82,15 @@ class CheckEulerAngles1Q(QiskitTestCase): def check_one_qubit_euler_angles(self, operator, tolerance=1e-14): """Check euler_angles_1q works for the given unitary""" - with self.subTest(operator=operator): - target_unitary = operator.data - angles = euler_angles_1q(target_unitary) - decomp_unitary = U3Gate(*angles).to_matrix() - target_unitary *= la.det(target_unitary)**(-0.5) - decomp_unitary *= la.det(decomp_unitary)**(-0.5) - maxdist = np.max(np.abs(target_unitary - decomp_unitary)) - if maxdist > 0.1: - maxdist = np.max(np.abs(target_unitary + decomp_unitary)) - self.assertTrue(np.abs(maxdist) < tolerance, "Worst distance {}".format(maxdist)) + target_unitary = operator.data + angles = euler_angles_1q(target_unitary) + decomp_unitary = U3Gate(*angles).to_matrix() + target_unitary *= la.det(target_unitary)**(-0.5) + decomp_unitary *= la.det(decomp_unitary)**(-0.5) + maxdist = np.max(np.abs(target_unitary - decomp_unitary)) + if maxdist > 0.1: + maxdist = np.max(np.abs(target_unitary + decomp_unitary)) + self.assertTrue(np.abs(maxdist) < tolerance, "Worst distance {}".format(maxdist)) @ddt class TestEulerAngles1Q(CheckEulerAngles1Q): From ebcb24f5fdf4f29b26c370f15a3c6c299313e198 Mon Sep 17 00:00:00 2001 From: Luciano Bello Date: Thu, 19 Dec 2019 12:57:21 -0500 Subject: [PATCH 12/49] all the checks in the same place --- test/python/quantum_info/test_synthesis.py | 109 +++++++++------------ 1 file changed, 49 insertions(+), 60 deletions(-) diff --git a/test/python/quantum_info/test_synthesis.py b/test/python/quantum_info/test_synthesis.py index d0eac3fa4df8..f43405d161a4 100644 --- a/test/python/quantum_info/test_synthesis.py +++ b/test/python/quantum_info/test_synthesis.py @@ -77,14 +77,19 @@ def make_hard_thetas_oneq(smallest=1e-18, factor=3.2, steps=22, phi=0.7, lam=0.9 [(0.2, 0.3, 0.1), (0.7, 0.15, 0.22), (0.001, 0.97, 2.2), (3.14, 2.1, 0.9)]]] -class CheckEulerAngles1Q(QiskitTestCase): - """Implements check_one_qubit_euler_angles()""" +class CheckDecompositions(QiskitTestCase): + """Implements decomposition checkers.""" - def check_one_qubit_euler_angles(self, operator, tolerance=1e-14): + def check_one_qubit_euler_angles(self, operator, basis=None, tolerance=1e-12): """Check euler_angles_1q works for the given unitary""" target_unitary = operator.data - angles = euler_angles_1q(target_unitary) - decomp_unitary = U3Gate(*angles).to_matrix() + if basis is None: + angles = euler_angles_1q(target_unitary) + decomp_unitary = U3Gate(*angles).to_matrix() + else: + decomposer = OneQubitEulerDecomposer(basis) + decomp_unitary = Operator(decomposer(target_unitary)).data + # Add global phase to make special unitary target_unitary *= la.det(target_unitary)**(-0.5) decomp_unitary *= la.det(decomp_unitary)**(-0.5) maxdist = np.max(np.abs(target_unitary - decomp_unitary)) @@ -92,8 +97,43 @@ def check_one_qubit_euler_angles(self, operator, tolerance=1e-14): maxdist = np.max(np.abs(target_unitary + decomp_unitary)) self.assertTrue(np.abs(maxdist) < tolerance, "Worst distance {}".format(maxdist)) + # FIXME: should be possible to set this tolerance tighter after improving the function + def check_two_qubit_weyl_decomposition(self, target_unitary, tolerance=1.e-7): + """Check TwoQubitWeylDecomposition() works for a given operator""" + # pylint: disable=invalid-name + decomp = TwoQubitWeylDecomposition(target_unitary) + op = Operator(np.eye(4)) + for u, qs in ( + (decomp.K2r, [0]), + (decomp.K2l, [1]), + (Ud(decomp.a, decomp.b, decomp.c), [0, 1]), + (decomp.K1r, [0]), + (decomp.K1l, [1]), + ): + op = op.compose(u, qs) + decomp_unitary = op.data + target_unitary *= la.det(target_unitary)**(-0.25) + decomp_unitary *= la.det(decomp_unitary)**(-0.25) + maxdists = [np.max(np.abs(target_unitary + phase*decomp_unitary)) + for phase in [1, 1j, -1, -1j]] + maxdist = np.min(maxdists) + self.assertTrue(np.abs(maxdist) < tolerance, "Worst distance {}".format(maxdist)) + + def check_exact_decomposition(self, target_unitary, decomposer, tolerance=1.e-7): + """Check exact decomposition for a particular target""" + decomp_circuit = decomposer(target_unitary) + result = execute(decomp_circuit, UnitarySimulatorPy()).result() + decomp_unitary = result.get_unitary() + target_unitary *= la.det(target_unitary) ** (-0.25) + decomp_unitary *= la.det(decomp_unitary) ** (-0.25) + maxdists = [np.max(np.abs(target_unitary + phase * decomp_unitary)) + for phase in [1, 1j, -1, -1j]] + maxdist = np.min(maxdists) + self.assertTrue(np.abs(maxdist) < tolerance, "Worst distance {}".format(maxdist)) + + @ddt -class TestEulerAngles1Q(CheckEulerAngles1Q): +class TestEulerAngles1Q(CheckDecompositions): """Test euler_angles_1q()""" def test_euler_angles_1q_clifford(self): @@ -115,25 +155,9 @@ def test_euler_angles_1q_random(self, seed): @ddt -class TestOneQubitEulerDecomposer(QiskitTestCase): +class TestOneQubitEulerDecomposer(CheckDecompositions): """Test OneQubitEulerDecomposer""" - def check_one_qubit_euler_angles(self, operator, basis='U3', - tolerance=1e-12): - """Check euler_angles_1q works for the given unitary""" - decomposer = OneQubitEulerDecomposer(basis) - with self.subTest(operator=operator): - target_unitary = operator.data - decomp_unitary = Operator(decomposer(target_unitary)).data - # Add global phase to make special unitary - target_unitary *= la.det(target_unitary)**(-0.5) - decomp_unitary *= la.det(decomp_unitary)**(-0.5) - maxdist = np.max(np.abs(target_unitary - decomp_unitary)) - if maxdist > 0.1: - maxdist = np.max(np.abs(target_unitary + decomp_unitary)) - self.assertTrue(np.abs(maxdist) < tolerance, - "Worst distance {}".format(maxdist)) - def test_one_qubit_clifford_u3_basis(self): """Verify for u3 basis and all Cliffords.""" for clifford in ONEQ_CLIFFORDS: @@ -219,32 +243,10 @@ def test_one_qubit_random_xyx_basis(self, seed): # FIXME: streamline the set of test cases -class TestTwoQubitWeylDecomposition(QiskitTestCase): +class TestTwoQubitWeylDecomposition(CheckDecompositions): """Test TwoQubitWeylDecomposition() """ - # pylint: disable=invalid-name - # FIXME: should be possible to set this tolerance tighter after improving the function - def check_two_qubit_weyl_decomposition(self, target_unitary, tolerance=1.e-7): - """Check TwoQubitWeylDecomposition() works for a given operator""" - with self.subTest(unitary=target_unitary): - decomp = TwoQubitWeylDecomposition(target_unitary) - op = Operator(np.eye(4)) - for u, qs in ( - (decomp.K2r, [0]), - (decomp.K2l, [1]), - (Ud(decomp.a, decomp.b, decomp.c), [0, 1]), - (decomp.K1r, [0]), - (decomp.K1l, [1]), - ): - op = op.compose(u, qs) - decomp_unitary = op.data - target_unitary *= la.det(target_unitary)**(-0.25) - decomp_unitary *= la.det(decomp_unitary)**(-0.25) - maxdists = [np.max(np.abs(target_unitary + phase*decomp_unitary)) - for phase in [1, 1j, -1, -1j]] - maxdist = np.min(maxdists) - self.assertTrue(np.abs(maxdist) < tolerance, "Worst distance {}".format(maxdist)) def test_two_qubit_weyl_decomposition_cnot(self): """Verify Weyl KAK decomposition for U~CNOT""" @@ -385,23 +387,10 @@ def test_two_qubit_weyl_decomposition_abc(self, smallest=1e-18, factor=9.8, step @ddt -class TestTwoQubitDecomposeExact(QiskitTestCase): +class TestTwoQubitDecomposeExact(CheckDecompositions): """Test TwoQubitBasisDecomposer() for exact decompositions """ - # pylint: disable=invalid-name - def check_exact_decomposition(self, target_unitary, decomposer, tolerance=1.e-7): - """Check exact decomposition for a particular target""" - with self.subTest(unitary=target_unitary, decomposer=decomposer): - decomp_circuit = decomposer(target_unitary) - result = execute(decomp_circuit, UnitarySimulatorPy()).result() - decomp_unitary = result.get_unitary() - target_unitary *= la.det(target_unitary)**(-0.25) - decomp_unitary *= la.det(decomp_unitary)**(-0.25) - maxdists = [np.max(np.abs(target_unitary + phase*decomp_unitary)) - for phase in [1, 1j, -1, -1j]] - maxdist = np.min(maxdists) - self.assertTrue(np.abs(maxdist) < tolerance, "Worst distance {}".format(maxdist)) def test_cnot_rxx_decompose(self): """Verify CNOT decomposition into RXX gate is correct""" From 583622f3ea16fc4826ac6179b60445fd92167f76 Mon Sep 17 00:00:00 2001 From: Luciano Bello Date: Thu, 19 Dec 2019 14:06:44 -0500 Subject: [PATCH 13/49] random tests! --- test/randomized/test_synthesis.py | 155 ++++++++++++++++++++++++++++++ 1 file changed, 155 insertions(+) create mode 100644 test/randomized/test_synthesis.py diff --git a/test/randomized/test_synthesis.py b/test/randomized/test_synthesis.py new file mode 100644 index 000000000000..3419940f4569 --- /dev/null +++ b/test/randomized/test_synthesis.py @@ -0,0 +1,155 @@ +# -*- coding: utf-8 -*- + +# This code is part of Qiskit. +# +# (C) Copyright IBM 2017, 2019. +# +# This code is licensed under the Apache License, Version 2.0. You may +# obtain a copy of this license in the LICENSE.txt file in the root directory +# of this source tree or at http://www.apache.org/licenses/LICENSE-2.0. +# +# Any modifications or derivative works of this code must retain this +# copyright notice, and modified files need to carry a notice indicating +# that they have been altered from the originals. + +"""Randomized tests of quantum synthesis.""" +import numpy as np +from hypothesis import given, strategies +import unittest + +from ..python.quantum_info.test_synthesis import CheckDecompositions + +from qiskit import execute +from qiskit.circuit import QuantumCircuit, QuantumRegister +from qiskit.extensions import UnitaryGate +from qiskit.providers.basicaer import UnitarySimulatorPy +from qiskit.quantum_info.random import random_unitary +from qiskit.quantum_info.synthesis.two_qubit_decompose import (two_qubit_cnot_decompose, + TwoQubitBasisDecomposer, + Ud) + + +class TestSynthesis(CheckDecompositions): + """Test synthesis""" + + @given(strategies.integers(min_value=0, max_value=2 ** 32 - 1)) + def test_1q_random(self, seed): + """Checks one qubit decompositions""" + unitary = random_unitary(2, seed=seed) + self.check_one_qubit_euler_angles(unitary) + self.check_one_qubit_euler_angles(unitary, 'U3') + self.check_one_qubit_euler_angles(unitary, 'U1X') + self.check_one_qubit_euler_angles(unitary, 'ZYZ') + self.check_one_qubit_euler_angles(unitary, 'ZXZ') + self.check_one_qubit_euler_angles(unitary, 'XYX') + + @given(strategies.integers(min_value=0, max_value=2 ** 32 - 1)) + def test_2q_random(self, seed): + """Checks two qubit decompositions""" + unitary = random_unitary(4, seed=seed) + self.check_exact_decomposition(unitary.data, two_qubit_cnot_decompose) + + @given(strategies.tuples(strategies.integers(min_value=0, max_value=2 ** 32 - 1), + strategies.integers(min_value=0, max_value=2 ** 32 - 1), + strategies.integers(min_value=0, max_value=2 ** 32 - 1), + strategies.integers(min_value=0, max_value=2 ** 32 - 1), + strategies.integers(min_value=0, max_value=2 ** 32 - 1))) + def test_exact_supercontrolled_decompose_random(self, seeds): + """Exact decomposition for random supercontrolled basis and random target""" + k1 = np.kron(random_unitary(2, seed=seeds[0]).data, random_unitary(2, seed=seeds[1]).data) + k2 = np.kron(random_unitary(2, seed=seeds[2]).data, random_unitary(2, seed=seeds[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=seeds[4]).data, decomposer) + + rotation = strategies.floats(min_value=0, max_value=2 ** 32 - 1) + + @given(strategies.tuples(*[rotation] * 6)) + def test_cx_equivalence_0cx_random(self, rnd): + """Check random circuits with 0 cx gates locally equivalent to identity. + """ + qr = QuantumRegister(2, name='q') + qc = QuantumCircuit(qr) + + qc.u3(rnd[0], rnd[1], rnd[2], qr[0]) + qc.u3(rnd[3], rnd[4], rnd[5], qr[1]) + + sim = UnitarySimulatorPy() + U = execute(qc, sim).result().get_unitary() + self.assertEqual(two_qubit_cnot_decompose.num_basis_gates(U), 0) + + @given(strategies.tuples(*[rotation] * 12)) + def test_cx_equivalence_1cx_random(self, rnd): + """Check random circuits with 1 cx gates locally equivalent to a cx. + """ + qr = QuantumRegister(2, name='q') + qc = QuantumCircuit(qr) + + qc.u3(rnd[0], rnd[1], rnd[2], qr[0]) + qc.u3(rnd[3], rnd[4], rnd[5], qr[1]) + + qc.cx(qr[1], qr[0]) + + qc.u3(rnd[6], rnd[7], rnd[8], qr[0]) + qc.u3(rnd[9], rnd[10], rnd[11], qr[1]) + + sim = UnitarySimulatorPy() + U = execute(qc, sim).result().get_unitary() + self.assertEqual(two_qubit_cnot_decompose.num_basis_gates(U), 1) + + @given(strategies.tuples(*[rotation] * 18)) + def test_cx_equivalence_2cx_random(self, rnd): + """Check random circuits with 2 cx gates locally equivalent to some circuit with 2 cx. + """ + qr = QuantumRegister(2, name='q') + qc = QuantumCircuit(qr) + + qc.u3(rnd[0], rnd[1], rnd[2], qr[0]) + qc.u3(rnd[3], rnd[4], rnd[5], qr[1]) + + qc.cx(qr[1], qr[0]) + + qc.u3(rnd[6], rnd[7], rnd[8], qr[0]) + qc.u3(rnd[9], rnd[10], rnd[11], qr[1]) + + qc.cx(qr[0], qr[1]) + + qc.u3(rnd[12], rnd[13], rnd[14], qr[0]) + qc.u3(rnd[15], rnd[16], rnd[17], qr[1]) + + sim = UnitarySimulatorPy() + U = execute(qc, sim).result().get_unitary() + self.assertEqual(two_qubit_cnot_decompose.num_basis_gates(U), 2) + + @given(strategies.tuples(*[rotation] * 24)) + def test_cx_equivalence_3cx_random(self, rnd): + """Check random circuits with 3 cx gates are outside the 0, 1, and 2 qubit regions. + """ + qr = QuantumRegister(2, name='q') + qc = QuantumCircuit(qr) + + qc.u3(rnd[0], rnd[1], rnd[2], qr[0]) + qc.u3(rnd[3], rnd[4], rnd[5], qr[1]) + + qc.cx(qr[1], qr[0]) + + qc.u3(rnd[6], rnd[7], rnd[8], qr[0]) + qc.u3(rnd[9], rnd[10], rnd[11], qr[1]) + + qc.cx(qr[0], qr[1]) + + qc.u3(rnd[12], rnd[13], rnd[14], qr[0]) + qc.u3(rnd[15], rnd[16], rnd[17], qr[1]) + + qc.cx(qr[1], qr[0]) + + qc.u3(rnd[18], rnd[19], rnd[20], qr[0]) + qc.u3(rnd[21], rnd[22], rnd[23], qr[1]) + + sim = UnitarySimulatorPy() + U = execute(qc, sim).result().get_unitary() + self.assertEqual(two_qubit_cnot_decompose.num_basis_gates(U), 3) + + +if __name__ == '__main__': + unittest.main() From 6e2b2709d8ffe702df8bce9a04089d8a9fb55245 Mon Sep 17 00:00:00 2001 From: Luciano Bello Date: Thu, 19 Dec 2019 14:10:51 -0500 Subject: [PATCH 14/49] rotation range --- test/randomized/test_synthesis.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/randomized/test_synthesis.py b/test/randomized/test_synthesis.py index 3419940f4569..f5bd99f88463 100644 --- a/test/randomized/test_synthesis.py +++ b/test/randomized/test_synthesis.py @@ -62,7 +62,7 @@ def test_exact_supercontrolled_decompose_random(self, seeds): decomposer = TwoQubitBasisDecomposer(UnitaryGate(basis_unitary)) self.check_exact_decomposition(random_unitary(4, seed=seeds[4]).data, decomposer) - rotation = strategies.floats(min_value=0, max_value=2 ** 32 - 1) + rotation = strategies.floats(min_value=-np.pi*10, max_value=np.pi*10) @given(strategies.tuples(*[rotation] * 6)) def test_cx_equivalence_0cx_random(self, rnd): From eb6d49e421ccc55f6413e2606e316deccd9e6368 Mon Sep 17 00:00:00 2001 From: Luciano Bello Date: Thu, 19 Dec 2019 16:12:08 -0500 Subject: [PATCH 15/49] lint --- test/python/quantum_info/test_synthesis.py | 18 +++++++++--------- test/randomized/test_synthesis.py | 21 +++++++++++---------- 2 files changed, 20 insertions(+), 19 deletions(-) diff --git a/test/python/quantum_info/test_synthesis.py b/test/python/quantum_info/test_synthesis.py index f43405d161a4..088186b5a1b3 100644 --- a/test/python/quantum_info/test_synthesis.py +++ b/test/python/quantum_info/test_synthesis.py @@ -390,7 +390,6 @@ def test_two_qubit_weyl_decomposition_abc(self, smallest=1e-18, factor=9.8, step class TestTwoQubitDecomposeExact(CheckDecompositions): """Test TwoQubitBasisDecomposer() for exact decompositions """ - # pylint: disable=invalid-name def test_cnot_rxx_decompose(self): """Verify CNOT decomposition into RXX gate is correct""" @@ -420,6 +419,7 @@ def test_exact_two_qubit_cnot_decompose_paulis(self): @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 @@ -441,8 +441,8 @@ def test_cx_equivalence_0cx(self): qc.u3(3.07225205, 2.47163021, 1.85387544, qr[1]) # generated w/ 2*np.pi*random(size=3) sim = UnitarySimulatorPy() - U = execute(qc, sim).result().get_unitary() - self.assertEqual(two_qubit_cnot_decompose.num_basis_gates(U), 0) + unitary = execute(qc, sim).result().get_unitary() + self.assertEqual(two_qubit_cnot_decompose.num_basis_gates(unitary), 0) def test_cx_equivalence_1cx(self): """Check circuits with 1 cx gates locally equivalent to a cx @@ -459,8 +459,8 @@ def test_cx_equivalence_1cx(self): qc.u3(4.27362122, 1.32003729, 4.84325493, qr[1]) # generated w/ 2*np.pi*random(size=3) sim = UnitarySimulatorPy() - U = execute(qc, sim).result().get_unitary() - self.assertEqual(two_qubit_cnot_decompose.num_basis_gates(U), 1) + unitary = execute(qc, sim).result().get_unitary() + self.assertEqual(two_qubit_cnot_decompose.num_basis_gates(unitary), 1) def test_cx_equivalence_2cx(self): """Check circuits with 2 cx gates locally equivalent to some circuit with 2 cx. @@ -482,8 +482,8 @@ def test_cx_equivalence_2cx(self): qc.u3(5.95780296, 6.13512175, 5.66765116, qr[1]) # generated w/ 2*np.pi*random(size=3) sim = UnitarySimulatorPy() - U = execute(qc, sim).result().get_unitary() - self.assertEqual(two_qubit_cnot_decompose.num_basis_gates(U), 2) + unitary = execute(qc, sim).result().get_unitary() + self.assertEqual(two_qubit_cnot_decompose.num_basis_gates(unitary), 2) def test_cx_equivalence_3cx(self): """Check circuits with 3 cx gates are outside the 0, 1, and 2 qubit regions. @@ -510,8 +510,8 @@ def test_cx_equivalence_3cx(self): qc.u3(4.92087635, 6.08781048, 4.85942885, qr[1]) # generated w/ 2*np.pi*random(size=3) sim = UnitarySimulatorPy() - U = execute(qc, sim).result().get_unitary() - self.assertEqual(two_qubit_cnot_decompose.num_basis_gates(U), 3) + unitary = execute(qc, sim).result().get_unitary() + self.assertEqual(two_qubit_cnot_decompose.num_basis_gates(unitary), 3) # FIXME: need to write tests for the approximate decompositions diff --git a/test/randomized/test_synthesis.py b/test/randomized/test_synthesis.py index f5bd99f88463..19ffe1f9577a 100644 --- a/test/randomized/test_synthesis.py +++ b/test/randomized/test_synthesis.py @@ -13,11 +13,10 @@ # that they have been altered from the originals. """Randomized tests of quantum synthesis.""" +import unittest import numpy as np from hypothesis import given, strategies -import unittest -from ..python.quantum_info.test_synthesis import CheckDecompositions from qiskit import execute from qiskit.circuit import QuantumCircuit, QuantumRegister @@ -27,6 +26,7 @@ from qiskit.quantum_info.synthesis.two_qubit_decompose import (two_qubit_cnot_decompose, TwoQubitBasisDecomposer, Ud) +from ..python.quantum_info.test_synthesis import CheckDecompositions class TestSynthesis(CheckDecompositions): @@ -56,6 +56,7 @@ def test_2q_random(self, seed): strategies.integers(min_value=0, max_value=2 ** 32 - 1))) def test_exact_supercontrolled_decompose_random(self, seeds): """Exact decomposition for random supercontrolled basis and random target""" + # pylint: disable=invalid-name k1 = np.kron(random_unitary(2, seed=seeds[0]).data, random_unitary(2, seed=seeds[1]).data) k2 = np.kron(random_unitary(2, seed=seeds[2]).data, random_unitary(2, seed=seeds[3]).data) basis_unitary = k1 @ Ud(np.pi / 4, 0, 0) @ k2 @@ -75,8 +76,8 @@ def test_cx_equivalence_0cx_random(self, rnd): qc.u3(rnd[3], rnd[4], rnd[5], qr[1]) sim = UnitarySimulatorPy() - U = execute(qc, sim).result().get_unitary() - self.assertEqual(two_qubit_cnot_decompose.num_basis_gates(U), 0) + unitary = execute(qc, sim).result().get_unitary() + self.assertEqual(two_qubit_cnot_decompose.num_basis_gates(unitary), 0) @given(strategies.tuples(*[rotation] * 12)) def test_cx_equivalence_1cx_random(self, rnd): @@ -94,8 +95,8 @@ def test_cx_equivalence_1cx_random(self, rnd): qc.u3(rnd[9], rnd[10], rnd[11], qr[1]) sim = UnitarySimulatorPy() - U = execute(qc, sim).result().get_unitary() - self.assertEqual(two_qubit_cnot_decompose.num_basis_gates(U), 1) + unitary = execute(qc, sim).result().get_unitary() + self.assertEqual(two_qubit_cnot_decompose.num_basis_gates(unitary), 1) @given(strategies.tuples(*[rotation] * 18)) def test_cx_equivalence_2cx_random(self, rnd): @@ -118,8 +119,8 @@ def test_cx_equivalence_2cx_random(self, rnd): qc.u3(rnd[15], rnd[16], rnd[17], qr[1]) sim = UnitarySimulatorPy() - U = execute(qc, sim).result().get_unitary() - self.assertEqual(two_qubit_cnot_decompose.num_basis_gates(U), 2) + unitary = execute(qc, sim).result().get_unitary() + self.assertEqual(two_qubit_cnot_decompose.num_basis_gates(unitary), 2) @given(strategies.tuples(*[rotation] * 24)) def test_cx_equivalence_3cx_random(self, rnd): @@ -147,8 +148,8 @@ def test_cx_equivalence_3cx_random(self, rnd): qc.u3(rnd[21], rnd[22], rnd[23], qr[1]) sim = UnitarySimulatorPy() - U = execute(qc, sim).result().get_unitary() - self.assertEqual(two_qubit_cnot_decompose.num_basis_gates(U), 3) + unitary = execute(qc, sim).result().get_unitary() + self.assertEqual(two_qubit_cnot_decompose.num_basis_gates(unitary), 3) if __name__ == '__main__': From f2a52372a099da7be8cabc30ade613344c88b70e Mon Sep 17 00:00:00 2001 From: Luciano Bello Date: Mon, 23 Dec 2019 09:57:35 -0500 Subject: [PATCH 16/49] Update test/python/quantum_info/test_random.py Co-Authored-By: Ali Javadi-Abhari --- test/python/quantum_info/test_random.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/python/quantum_info/test_random.py b/test/python/quantum_info/test_random.py index 50664379640c..6fa3dbf1dc9f 100644 --- a/test/python/quantum_info/test_random.py +++ b/test/python/quantum_info/test_random.py @@ -28,7 +28,7 @@ class TestRandomUtils(QiskitTestCase): def test_seeded_random_unitary(self): """Given the same seed, the output should be expected. - Following the numpy approach we are going to try to keep the policy of platform-independent + Following the numpy approach we are going to keep the policy of platform-independence with randomness. https://stackoverflow.com/questions/40676205/cross-platform-numpy-random-seed""" seed = 314159 From 8f115bf2e009e751b48a58582ccfee91e05ffd64 Mon Sep 17 00:00:00 2001 From: Luciano Bello Date: Mon, 23 Dec 2019 10:11:16 -0500 Subject: [PATCH 17/49] more info in test_unitary and test_density_matrix docstring --- test/python/quantum_info/test_random.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/test/python/quantum_info/test_random.py b/test/python/quantum_info/test_random.py index 6fa3dbf1dc9f..4b1229d17c0b 100644 --- a/test/python/quantum_info/test_random.py +++ b/test/python/quantum_info/test_random.py @@ -44,8 +44,8 @@ def test_seeded_random_unitary(self): assert_allclose(unitary.data, expected, atol=1e-8) def test_unitary(self): - """ Test that a random unitary with set seed will not affect later - results + """ Test that a random unitary with set seed will not affect later results. + https://github.com/Qiskit/qiskit-terra/issues/2850 """ seed = 314159 test_cases = 100 @@ -57,8 +57,8 @@ def test_unitary(self): self.assertFalse(array_equality) def test_density_matrix(self): - """ Test that a random state with set seed will not affect later - results. + """ Test that a random state with set seed will not affect later results. + https://github.com/Qiskit/qiskit-terra/issues/2850 """ seed = 314159 test_cases = 100 From 5600733ae905181db391f8fc05a856ad04af4904 Mon Sep 17 00:00:00 2001 From: Luciano Bello Date: Fri, 27 Dec 2019 09:50:43 -0500 Subject: [PATCH 18/49] tolerance --- test/python/quantum_info/test_synthesis.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/python/quantum_info/test_synthesis.py b/test/python/quantum_info/test_synthesis.py index 088186b5a1b3..a1bc2ca4d345 100644 --- a/test/python/quantum_info/test_synthesis.py +++ b/test/python/quantum_info/test_synthesis.py @@ -80,7 +80,7 @@ def make_hard_thetas_oneq(smallest=1e-18, factor=3.2, steps=22, phi=0.7, lam=0.9 class CheckDecompositions(QiskitTestCase): """Implements decomposition checkers.""" - def check_one_qubit_euler_angles(self, operator, basis=None, tolerance=1e-12): + def check_one_qubit_euler_angles(self, operator, basis=None, tolerance=1e-14): """Check euler_angles_1q works for the given unitary""" target_unitary = operator.data if basis is None: From 37bbd99cb45ad6186525b608ebab4a06a95972ff Mon Sep 17 00:00:00 2001 From: Luciano Bello Date: Fri, 27 Dec 2019 09:55:34 -0500 Subject: [PATCH 19/49] operator in message --- test/python/quantum_info/test_synthesis.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/test/python/quantum_info/test_synthesis.py b/test/python/quantum_info/test_synthesis.py index a1bc2ca4d345..c30adf3524b6 100644 --- a/test/python/quantum_info/test_synthesis.py +++ b/test/python/quantum_info/test_synthesis.py @@ -95,7 +95,8 @@ def check_one_qubit_euler_angles(self, operator, basis=None, tolerance=1e-14): maxdist = np.max(np.abs(target_unitary - decomp_unitary)) if maxdist > 0.1: maxdist = np.max(np.abs(target_unitary + decomp_unitary)) - self.assertTrue(np.abs(maxdist) < tolerance, "Worst distance {}".format(maxdist)) + self.assertTrue(np.abs(maxdist) < tolerance, + "Operator {}: Worst distance {}".format(operator, maxdist)) # FIXME: should be possible to set this tolerance tighter after improving the function def check_two_qubit_weyl_decomposition(self, target_unitary, tolerance=1.e-7): From 22a6e93c8fb7ce7aa129d711a5e0597557be6857 Mon Sep 17 00:00:00 2001 From: Luciano Bello Date: Fri, 27 Dec 2019 10:02:38 -0500 Subject: [PATCH 20/49] unitary in message --- test/python/quantum_info/test_synthesis.py | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/test/python/quantum_info/test_synthesis.py b/test/python/quantum_info/test_synthesis.py index c30adf3524b6..d605281b1122 100644 --- a/test/python/quantum_info/test_synthesis.py +++ b/test/python/quantum_info/test_synthesis.py @@ -96,7 +96,7 @@ def check_one_qubit_euler_angles(self, operator, basis=None, tolerance=1e-14): if maxdist > 0.1: maxdist = np.max(np.abs(target_unitary + decomp_unitary)) self.assertTrue(np.abs(maxdist) < tolerance, - "Operator {}: Worst distance {}".format(operator, maxdist)) + "Operator {}: Worst distance {}".format(operator, maxdist)) # FIXME: should be possible to set this tolerance tighter after improving the function def check_two_qubit_weyl_decomposition(self, target_unitary, tolerance=1.e-7): @@ -118,7 +118,8 @@ def check_two_qubit_weyl_decomposition(self, target_unitary, tolerance=1.e-7): maxdists = [np.max(np.abs(target_unitary + phase*decomp_unitary)) for phase in [1, 1j, -1, -1j]] maxdist = np.min(maxdists) - self.assertTrue(np.abs(maxdist) < tolerance, "Worst distance {}".format(maxdist)) + self.assertTrue(np.abs(maxdist) < tolerance, + "Unitary {}: Worst distance {}".format(target_unitary, maxdist)) def check_exact_decomposition(self, target_unitary, decomposer, tolerance=1.e-7): """Check exact decomposition for a particular target""" @@ -130,8 +131,8 @@ def check_exact_decomposition(self, target_unitary, decomposer, tolerance=1.e-7) maxdists = [np.max(np.abs(target_unitary + phase * decomp_unitary)) for phase in [1, 1j, -1, -1j]] maxdist = np.min(maxdists) - self.assertTrue(np.abs(maxdist) < tolerance, "Worst distance {}".format(maxdist)) - + self.assertTrue(np.abs(maxdist) < tolerance, + "Unitary {}: Worst distance {}".format(target_unitary, maxdist)) @ddt class TestEulerAngles1Q(CheckDecompositions): From 02f8a1f1e9587c4d9ca814b128a616ce69908b3f Mon Sep 17 00:00:00 2001 From: Luciano Bello Date: Fri, 27 Dec 2019 10:13:17 -0500 Subject: [PATCH 21/49] increase range --- test/python/quantum_info/test_synthesis.py | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/test/python/quantum_info/test_synthesis.py b/test/python/quantum_info/test_synthesis.py index d605281b1122..cc8e97084472 100644 --- a/test/python/quantum_info/test_synthesis.py +++ b/test/python/quantum_info/test_synthesis.py @@ -213,31 +213,31 @@ def test_one_qubit_hard_thetas_xyx_basis(self): for gate in HARD_THETA_ONEQS: self.check_one_qubit_euler_angles(Operator(gate), 'XYX') - @combine(seed=range(10), name='test_one_qubit_random_u3_basis_{seed}') + @combine(seed=range(50), name='test_one_qubit_random_u3_basis_{seed}') def test_one_qubit_random_u3_basis(self, seed): """Verify for u3 basis and random_unitary (seed={seed}).""" unitary = random_unitary(2, seed=seed) self.check_one_qubit_euler_angles(unitary, 'U3') - @combine(seed=range(10), name='test_one_qubit_random_u1x_basis_{seed}') + @combine(seed=range(50), name='test_one_qubit_random_u1x_basis_{seed}') def test_one_qubit_random_u1x_basis(self, seed): """Verify for u1, x90 basis and random_unitary (seed={seed}).""" unitary = random_unitary(2, seed=seed) self.check_one_qubit_euler_angles(unitary, 'U1X') - @combine(seed=range(10), name='test_one_qubit_random_zyz_basis_{seed}') + @combine(seed=range(50), name='test_one_qubit_random_zyz_basis_{seed}') def test_one_qubit_random_zyz_basis(self, seed): """Verify for rz, ry, rz basis and random_unitary (seed={seed}).""" unitary = random_unitary(2, seed=seed) self.check_one_qubit_euler_angles(unitary, 'ZYZ') - @combine(seed=range(10), name='test_one_qubit_random_zxz_basis_{seed}') + @combine(seed=range(50), name='test_one_qubit_random_zxz_basis_{seed}') def test_one_qubit_random_zxz_basis(self, seed): """Verify for rz, rx, rz basis and random_unitary (seed={seed}).""" unitary = random_unitary(2, seed=seed) self.check_one_qubit_euler_angles(unitary, 'ZXZ') - @combine(seed=range(10), name='test_one_qubit_random_xyx_basis_{seed}') + @combine(seed=range(50), name='test_one_qubit_random_xyx_basis_{seed}') def test_one_qubit_random_xyx_basis(self, seed): """Verify for rx, ry, rx basis and random_unitary (seed={seed}).""" unitary = random_unitary(2, seed=seed) From 94f862a8390e154511bf6f67fe16893f21894545 Mon Sep 17 00:00:00 2001 From: Luciano Bello Date: Fri, 27 Dec 2019 10:48:37 -0500 Subject: [PATCH 22/49] back to 1e-12 --- test/python/quantum_info/test_synthesis.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/python/quantum_info/test_synthesis.py b/test/python/quantum_info/test_synthesis.py index cc8e97084472..382ed37a9849 100644 --- a/test/python/quantum_info/test_synthesis.py +++ b/test/python/quantum_info/test_synthesis.py @@ -80,7 +80,7 @@ def make_hard_thetas_oneq(smallest=1e-18, factor=3.2, steps=22, phi=0.7, lam=0.9 class CheckDecompositions(QiskitTestCase): """Implements decomposition checkers.""" - def check_one_qubit_euler_angles(self, operator, basis=None, tolerance=1e-14): + def check_one_qubit_euler_angles(self, operator, basis=None, tolerance=1e-12): """Check euler_angles_1q works for the given unitary""" target_unitary = operator.data if basis is None: From ead5c0ea97248c6d61ff652182786c429a2921ac Mon Sep 17 00:00:00 2001 From: Luciano Bello Date: Fri, 27 Dec 2019 11:08:41 -0500 Subject: [PATCH 23/49] tolerance --- test/python/quantum_info/test_synthesis.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/test/python/quantum_info/test_synthesis.py b/test/python/quantum_info/test_synthesis.py index 382ed37a9849..98b83ebb3eda 100644 --- a/test/python/quantum_info/test_synthesis.py +++ b/test/python/quantum_info/test_synthesis.py @@ -80,15 +80,17 @@ def make_hard_thetas_oneq(smallest=1e-18, factor=3.2, steps=22, phi=0.7, lam=0.9 class CheckDecompositions(QiskitTestCase): """Implements decomposition checkers.""" - def check_one_qubit_euler_angles(self, operator, basis=None, tolerance=1e-12): + def check_one_qubit_euler_angles(self, operator, basis=None): """Check euler_angles_1q works for the given unitary""" target_unitary = operator.data if basis is None: angles = euler_angles_1q(target_unitary) decomp_unitary = U3Gate(*angles).to_matrix() + tolerance = 1e-14 else: decomposer = OneQubitEulerDecomposer(basis) decomp_unitary = Operator(decomposer(target_unitary)).data + tolerance = 1e-12 # Add global phase to make special unitary target_unitary *= la.det(target_unitary)**(-0.5) decomp_unitary *= la.det(decomp_unitary)**(-0.5) From efb4eb484e8a6e0a0b54851965aab6bf781bccb5 Mon Sep 17 00:00:00 2001 From: Luciano Bello Date: Fri, 27 Dec 2019 11:19:54 -0500 Subject: [PATCH 24/49] remove relative import --- test/randomized/test_synthesis.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/randomized/test_synthesis.py b/test/randomized/test_synthesis.py index 19ffe1f9577a..7be295c1ea8f 100644 --- a/test/randomized/test_synthesis.py +++ b/test/randomized/test_synthesis.py @@ -26,7 +26,7 @@ from qiskit.quantum_info.synthesis.two_qubit_decompose import (two_qubit_cnot_decompose, TwoQubitBasisDecomposer, Ud) -from ..python.quantum_info.test_synthesis import CheckDecompositions +from test.python.quantum_info.test_synthesis import CheckDecompositions class TestSynthesis(CheckDecompositions): From 820b616971f9ed58950ad404e8e112a07628bea9 Mon Sep 17 00:00:00 2001 From: Luciano Bello Date: Fri, 27 Dec 2019 11:35:01 -0500 Subject: [PATCH 25/49] keep parameter --- test/python/quantum_info/test_synthesis.py | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/test/python/quantum_info/test_synthesis.py b/test/python/quantum_info/test_synthesis.py index 98b83ebb3eda..e48f7838c92f 100644 --- a/test/python/quantum_info/test_synthesis.py +++ b/test/python/quantum_info/test_synthesis.py @@ -80,17 +80,15 @@ def make_hard_thetas_oneq(smallest=1e-18, factor=3.2, steps=22, phi=0.7, lam=0.9 class CheckDecompositions(QiskitTestCase): """Implements decomposition checkers.""" - def check_one_qubit_euler_angles(self, operator, basis=None): + def check_one_qubit_euler_angles(self, operator, basis=None, tolerance=1e-12): """Check euler_angles_1q works for the given unitary""" target_unitary = operator.data if basis is None: angles = euler_angles_1q(target_unitary) decomp_unitary = U3Gate(*angles).to_matrix() - tolerance = 1e-14 else: decomposer = OneQubitEulerDecomposer(basis) decomp_unitary = Operator(decomposer(target_unitary)).data - tolerance = 1e-12 # Add global phase to make special unitary target_unitary *= la.det(target_unitary)**(-0.5) decomp_unitary *= la.det(decomp_unitary)**(-0.5) @@ -203,12 +201,12 @@ def test_one_qubit_hard_thetas_u1x_basis(self): def test_one_qubit_hard_thetas_zyz_basis(self): """Verify for rz, ry, rz basis and close-to-degenerate theta.""" for gate in HARD_THETA_ONEQS: - self.check_one_qubit_euler_angles(Operator(gate), 'ZYZ') + self.check_one_qubit_euler_angles(Operator(gate), 'ZYZ', 1e-12) def test_one_qubit_hard_thetas_zxz_basis(self): """Verify for rz, rx, rz basis and close-to-degenerate theta.""" for gate in HARD_THETA_ONEQS: - self.check_one_qubit_euler_angles(Operator(gate), 'ZXZ') + self.check_one_qubit_euler_angles(Operator(gate), 'ZXZ', 1e-12) def test_one_qubit_hard_thetas_xyx_basis(self): """Verify for rx, ry, rx basis and close-to-degenerate theta.""" From 0d876dee3dc19325b703d91e89d1cb443c0c5cb8 Mon Sep 17 00:00:00 2001 From: Luciano Bello Date: Fri, 27 Dec 2019 11:45:02 -0500 Subject: [PATCH 26/49] seeding --- test/python/quantum_info/test_synthesis.py | 60 +++++++++++++--------- 1 file changed, 36 insertions(+), 24 deletions(-) diff --git a/test/python/quantum_info/test_synthesis.py b/test/python/quantum_info/test_synthesis.py index e48f7838c92f..24cc35e960d0 100644 --- a/test/python/quantum_info/test_synthesis.py +++ b/test/python/quantum_info/test_synthesis.py @@ -433,83 +433,95 @@ def test_exact_nonsupercontrolled_decompose(self): 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): + def test_cx_equivalence_0cx(self, seed=0): """Check circuits with 0 cx gates locally equivalent to identity """ + state = np.random.RandomState(seed) + rnd = 2 * np.pi * state.random(size=6) + qr = QuantumRegister(2, name='q') qc = QuantumCircuit(qr) - qc.u3(5.93716757, 5.12060183, 1.77882926, qr[0]) # generated w/ 2*np.pi*random(size=3) - qc.u3(3.07225205, 2.47163021, 1.85387544, qr[1]) # generated w/ 2*np.pi*random(size=3) + qc.u3(rnd[0], rnd[1], rnd[2], qr[0]) + qc.u3(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) - def test_cx_equivalence_1cx(self): + def test_cx_equivalence_1cx(self, seed=1): """Check circuits with 1 cx gates locally equivalent to a cx """ + state = np.random.RandomState(seed) + rnd = 2 * np.pi * state.random(size=12) + qr = QuantumRegister(2, name='q') qc = QuantumCircuit(qr) - qc.u3(5.93716757, 5.12060183, 1.77882926, qr[0]) # generated w/ 2*np.pi*random(size=3) - qc.u3(3.07225205, 2.47163021, 1.85387544, qr[1]) # generated w/ 2*np.pi*random(size=3) + qc.u3(rnd[0], rnd[1], rnd[2], qr[0]) + qc.u3(rnd[3], rnd[4], rnd[5], qr[1]) qc.cx(qr[1], qr[0]) - qc.u3(2.33171121, 4.71902488, 4.86059273, qr[0]) # generated w/ 2*np.pi*random(size=3) - qc.u3(4.27362122, 1.32003729, 4.84325493, qr[1]) # generated w/ 2*np.pi*random(size=3) + qc.u3(rnd[6], rnd[7], rnd[8], qr[0]) + qc.u3(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) - def test_cx_equivalence_2cx(self): + 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.RandomState(seed) + rnd = 2 * np.pi * state.random(size=18) + qr = QuantumRegister(2, name='q') qc = QuantumCircuit(qr) - qc.u3(5.93716757, 5.12060183, 1.77882926, qr[0]) # generated w/ 2*np.pi*random(size=3) - qc.u3(3.07225205, 2.47163021, 1.85387544, qr[1]) # generated w/ 2*np.pi*random(size=3) + qc.u3(rnd[0], rnd[1], rnd[2], qr[0]) + qc.u3(rnd[3], rnd[4], rnd[5], qr[1]) qc.cx(qr[1], qr[0]) - qc.u3(2.33171121, 4.71902488, 4.86059273, qr[0]) # generated w/ 2*np.pi*random(size=3) - qc.u3(4.27362122, 1.32003729, 4.84325493, qr[1]) # generated w/ 2*np.pi*random(size=3) + qc.u3(rnd[6], rnd[7], rnd[8], qr[0]) + qc.u3(rnd[9], rnd[10], rnd[11], qr[1]) qc.cx(qr[0], qr[1]) - qc.u3(5.33187487, 3.67914857, 1.51437625, qr[0]) # generated w/ 2*np.pi*random(size=3) - qc.u3(5.95780296, 6.13512175, 5.66765116, qr[1]) # generated w/ 2*np.pi*random(size=3) + qc.u3(rnd[12], rnd[13], rnd[14], qr[0]) + qc.u3(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) - def test_cx_equivalence_3cx(self): + 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.RandomState(seed) + rnd = 2 * np.pi * state.random(size=24) + qr = QuantumRegister(2, name='q') qc = QuantumCircuit(qr) - qc.u3(5.93716757, 5.12060183, 1.77882926, qr[0]) # generated w/ 2*np.pi*random(size=3) - qc.u3(3.07225205, 2.47163021, 1.85387544, qr[1]) # generated w/ 2*np.pi*random(size=3) + qc.u3(rnd[0], rnd[1], rnd[2], qr[0]) + qc.u3(rnd[3], rnd[4], rnd[5], qr[1]) qc.cx(qr[1], qr[0]) - qc.u3(2.33171121, 4.71902488, 4.86059273, qr[0]) # generated w/ 2*np.pi*random(size=3) - qc.u3(4.27362122, 1.32003729, 4.84325493, qr[1]) # generated w/ 2*np.pi*random(size=3) + qc.u3(rnd[6], rnd[7], rnd[8], qr[0]) + qc.u3(rnd[9], rnd[10], rnd[11], qr[1]) qc.cx(qr[0], qr[1]) - qc.u3(5.33187487, 3.67914857, 1.51437625, qr[0]) # generated w/ 2*np.pi*random(size=3) - qc.u3(5.95780296, 6.13512175, 5.66765116, qr[1]) # generated w/ 2*np.pi*random(size=3) + qc.u3(rnd[12], rnd[13], rnd[14], qr[0]) + qc.u3(rnd[15], rnd[16], rnd[17], qr[1]) qc.cx(qr[1], qr[0]) - qc.u3(4.77964448, 4.71461107, 0.60003097, qr[0]) # generated w/ 2*np.pi*random(size=3) - qc.u3(4.92087635, 6.08781048, 4.85942885, qr[1]) # generated w/ 2*np.pi*random(size=3) + qc.u3(rnd[18], rnd[19], rnd[20], qr[0]) + qc.u3(rnd[21], rnd[22], rnd[23], qr[1]) sim = UnitarySimulatorPy() unitary = execute(qc, sim).result().get_unitary() From 4c04d99abb5407cdc061001145d0deab4b9efea4 Mon Sep 17 00:00:00 2001 From: Luciano Bello Date: Fri, 27 Dec 2019 12:43:28 -0500 Subject: [PATCH 27/49] lint --- test/python/quantum_info/test_synthesis.py | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/test/python/quantum_info/test_synthesis.py b/test/python/quantum_info/test_synthesis.py index 24cc35e960d0..e75e74779291 100644 --- a/test/python/quantum_info/test_synthesis.py +++ b/test/python/quantum_info/test_synthesis.py @@ -96,7 +96,7 @@ def check_one_qubit_euler_angles(self, operator, basis=None, tolerance=1e-12): if maxdist > 0.1: maxdist = np.max(np.abs(target_unitary + decomp_unitary)) self.assertTrue(np.abs(maxdist) < tolerance, - "Operator {}: Worst distance {}".format(operator, maxdist)) + "Operator {}: Worst distance {}".format(operator, maxdist)) # FIXME: should be possible to set this tolerance tighter after improving the function def check_two_qubit_weyl_decomposition(self, target_unitary, tolerance=1.e-7): @@ -113,13 +113,13 @@ def check_two_qubit_weyl_decomposition(self, target_unitary, tolerance=1.e-7): ): op = op.compose(u, qs) decomp_unitary = op.data - target_unitary *= la.det(target_unitary)**(-0.25) - decomp_unitary *= la.det(decomp_unitary)**(-0.25) - maxdists = [np.max(np.abs(target_unitary + phase*decomp_unitary)) + target_unitary *= la.det(target_unitary) ** (-0.25) + decomp_unitary *= la.det(decomp_unitary) ** (-0.25) + maxdists = [np.max(np.abs(target_unitary + phase * decomp_unitary)) for phase in [1, 1j, -1, -1j]] maxdist = np.min(maxdists) self.assertTrue(np.abs(maxdist) < tolerance, - "Unitary {}: Worst distance {}".format(target_unitary, maxdist)) + "Unitary {}: Worst distance {}".format(target_unitary, maxdist)) def check_exact_decomposition(self, target_unitary, decomposer, tolerance=1.e-7): """Check exact decomposition for a particular target""" @@ -132,7 +132,8 @@ def check_exact_decomposition(self, target_unitary, decomposer, tolerance=1.e-7) for phase in [1, 1j, -1, -1j]] maxdist = np.min(maxdists) self.assertTrue(np.abs(maxdist) < tolerance, - "Unitary {}: Worst distance {}".format(target_unitary, maxdist)) + "Unitary {}: Worst distance {}".format(target_unitary, maxdist)) + @ddt class TestEulerAngles1Q(CheckDecompositions): @@ -248,6 +249,7 @@ def test_one_qubit_random_xyx_basis(self, seed): class TestTwoQubitWeylDecomposition(CheckDecompositions): """Test TwoQubitWeylDecomposition() """ + # pylint: disable=invalid-name def test_two_qubit_weyl_decomposition_cnot(self): @@ -527,6 +529,7 @@ def test_cx_equivalence_3cx(self, seed=3): unitary = execute(qc, sim).result().get_unitary() self.assertEqual(two_qubit_cnot_decompose.num_basis_gates(unitary), 3) + # FIXME: need to write tests for the approximate decompositions From 00b25be5419eca5a031e2513c000be675312463a Mon Sep 17 00:00:00 2001 From: Luciano Bello Date: Fri, 27 Dec 2019 12:58:57 -0500 Subject: [PATCH 28/49] import order --- test/randomized/test_synthesis.py | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/test/randomized/test_synthesis.py b/test/randomized/test_synthesis.py index 7be295c1ea8f..dab45c3967fa 100644 --- a/test/randomized/test_synthesis.py +++ b/test/randomized/test_synthesis.py @@ -14,9 +14,9 @@ """Randomized tests of quantum synthesis.""" import unittest -import numpy as np +from test.python.quantum_info.test_synthesis import CheckDecompositions from hypothesis import given, strategies - +import numpy as np from qiskit import execute from qiskit.circuit import QuantumCircuit, QuantumRegister @@ -26,8 +26,6 @@ from qiskit.quantum_info.synthesis.two_qubit_decompose import (two_qubit_cnot_decompose, TwoQubitBasisDecomposer, Ud) -from test.python.quantum_info.test_synthesis import CheckDecompositions - class TestSynthesis(CheckDecompositions): """Test synthesis""" From d94e46f995f59f9b44d978ce0686d683aa165ea1 Mon Sep 17 00:00:00 2001 From: Luciano Bello Date: Fri, 27 Dec 2019 13:15:38 -0500 Subject: [PATCH 29/49] lint! --- test/randomized/test_synthesis.py | 1 + 1 file changed, 1 insertion(+) diff --git a/test/randomized/test_synthesis.py b/test/randomized/test_synthesis.py index dab45c3967fa..92d8ec7bef22 100644 --- a/test/randomized/test_synthesis.py +++ b/test/randomized/test_synthesis.py @@ -27,6 +27,7 @@ TwoQubitBasisDecomposer, Ud) + class TestSynthesis(CheckDecompositions): """Test synthesis""" From 30f4fd97fb2d0edf9c100eebf50fe8bb6989e770 Mon Sep 17 00:00:00 2001 From: Luciano Bello Date: Fri, 17 Jan 2020 08:14:21 -0300 Subject: [PATCH 30/49] duplicated tests --- test/python/quantum_info/test_synthesis.py | 29 ---------------------- 1 file changed, 29 deletions(-) diff --git a/test/python/quantum_info/test_synthesis.py b/test/python/quantum_info/test_synthesis.py index 8903577f8bf5..aad208c3c71f 100644 --- a/test/python/quantum_info/test_synthesis.py +++ b/test/python/quantum_info/test_synthesis.py @@ -187,12 +187,6 @@ def test_one_qubit_hard_thetas_u3_basis(self): for gate in HARD_THETA_ONEQS: self.check_one_qubit_euler_angles(Operator(gate), 'U3') - @combine(seed=range(50), name='test_one_qubit_random_u3_basis_{seed}') - def test_one_qubit_random_u3_basis(self, seed): - """Verify for u3 basis and random unitaries (seed={seed}).""" - unitary = random_unitary(2, seed=seed) - self.check_one_qubit_euler_angles(unitary, 'U3') - # U1, X90 basis def test_one_qubit_clifford_u1x_basis(self): """Verify for u1, x90 basis and all Cliffords.""" @@ -212,29 +206,12 @@ def test_one_qubit_hard_thetas_zyz_basis(self): for gate in HARD_THETA_ONEQS: self.check_one_qubit_euler_angles(Operator(gate), 'ZYZ', 1e-12) - @combine(seed=range(50), name='test_one_qubit_random_u1x_basis_{seed}') - def test_one_qubit_random_u1x_basis(self, seed): - """Verify for u1, x90 basis and random unitaries (seed={seed}).""" - unitary = random_unitary(2, seed=seed) - self.check_one_qubit_euler_angles(unitary, 'U1X') - # Rz, Ry, Rz basis def test_one_qubit_clifford_zyz_basis(self): """Verify for rz, ry, rz basis and all Cliffords.""" for clifford in ONEQ_CLIFFORDS: self.check_one_qubit_euler_angles(clifford, 'ZYZ') - def test_one_qubit_hard_thetas_zyz_basis(self): - """Verify for rz, ry, rz basis and close-to-degenerate theta.""" - for gate in HARD_THETA_ONEQS: - self.check_one_qubit_euler_angles(Operator(gate), 'ZYZ') - - @combine(seed=range(50), name='test_one_qubit_random_zyz_basis_{seed}') - def test_one_qubit_random_zyz_basis(self, seed): - """Verify for rz, ry, rz basis and random unitaries (seed={seed}.""" - unitary = random_unitary(2, seed=seed) - self.check_one_qubit_euler_angles(unitary, 'ZYZ') - # Rz, Rx, Rz basis def test_one_qubit_clifford_zxz_basis(self): """Verify for rz, rx, rz basis and all Cliffords.""" @@ -246,12 +223,6 @@ def test_one_qubit_hard_thetas_zxz_basis(self): for gate in HARD_THETA_ONEQS: self.check_one_qubit_euler_angles(Operator(gate), 'ZXZ', 1e-12) - @combine(seed=range(50), name='test_one_qubit_random_zxz_basis_{seed}') - def test_one_qubit_random_zxz_basis(self, seed): - """Verify for rz, rx, rz basis and random unitaries (seed={seed}).""" - unitary = random_unitary(2, seed=seed) - self.check_one_qubit_euler_angles(unitary, 'ZXZ') - # Rx, Ry, Rx basis def test_one_qubit_clifford_xyx_basis(self): """Verify for rx, ry, rx basis and all Cliffords.""" From 9433754657c5ea850a99deaa514a8985a138b032 Mon Sep 17 00:00:00 2001 From: Luciano Bello Date: Sun, 1 Mar 2020 11:39:02 -0500 Subject: [PATCH 31/49] lint --- test/python/quantum_info/test_synthesis.py | 1 - 1 file changed, 1 deletion(-) diff --git a/test/python/quantum_info/test_synthesis.py b/test/python/quantum_info/test_synthesis.py index 771fb36cdbe9..07816db8f83b 100644 --- a/test/python/quantum_info/test_synthesis.py +++ b/test/python/quantum_info/test_synthesis.py @@ -159,7 +159,6 @@ def test_euler_angles_1q_random(self, seed): @ddt class TestOneQubitEulerDecomposer(CheckDecompositions): """Test OneQubitEulerDecomposer""" - def check_one_qubit_euler_angles(self, operator, basis='U3', tolerance=1e-12, phase_equal=False): From 5a29fc58b7c67663d5a407a16e8e8809f61a850f Mon Sep 17 00:00:00 2001 From: Luciano Bello Date: Mon, 2 Mar 2020 10:17:49 -0500 Subject: [PATCH 32/49] use the docstring from the test if no dsc is provided --- qiskit/test/utils.py | 8 ++++---- test/__init__.py | 3 +-- 2 files changed, 5 insertions(+), 6 deletions(-) diff --git a/qiskit/test/utils.py b/qiskit/test/utils.py index 71cfc304e665..0efb162f1b54 100644 --- a/qiskit/test/utils.py +++ b/qiskit/test/utils.py @@ -95,21 +95,21 @@ def __exit__(self, exc_type, exc_value, tb): class Case(dict): - """ A test case, see https://ddt.readthedocs.io/en/latest/example.html MyList.""" + """""" pass -def generate_cases(dsc=None, name=None, **kwargs): +def generate_cases(docstring, dsc=None, name=None, **kwargs): """Combines kwargs in cartesian product and creates Case with them""" ret = [] keys = kwargs.keys() vals = kwargs.values() for values in product(*vals): case = Case(zip(keys, values)) + if docstring is not None: + setattr(case, "__doc__", docstring.format(**case)) if dsc is not None: setattr(case, "__doc__", dsc.format(**case)) - else: - setattr(case, "__doc__", case.__doc__.format(**case)) if name is not None: setattr(case, "__name__", name.format(**case)) ret.append(case) diff --git a/test/__init__.py b/test/__init__.py index 4618b5736e6d..259b27ac6edb 100644 --- a/test/__init__.py +++ b/test/__init__.py @@ -27,6 +27,5 @@ def combine(**kwargs): """ def deco(func): - return data(*generate_cases(**kwargs))(unpack(func)) - + return data(*generate_cases(docstring=func.__doc__, **kwargs))(unpack(func)) return deco From ee2a184d73ef067021f0f09461c8cc53acc1878c Mon Sep 17 00:00:00 2001 From: Luciano Bello Date: Mon, 2 Mar 2020 11:05:50 -0500 Subject: [PATCH 33/49] lint --- test/python/quantum_info/test_synthesis.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/test/python/quantum_info/test_synthesis.py b/test/python/quantum_info/test_synthesis.py index 07816db8f83b..e62b93eac248 100644 --- a/test/python/quantum_info/test_synthesis.py +++ b/test/python/quantum_info/test_synthesis.py @@ -79,7 +79,8 @@ def make_hard_thetas_oneq(smallest=1e-18, factor=3.2, steps=22, phi=0.7, lam=0.9 class CheckDecompositions(QiskitTestCase): """Implements decomposition checkers.""" - def check_one_qubit_euler_angles(self, operator, basis=None, tolerance=1e-12): + def check_one_qubit_euler_angles(self, operator, basis=None, tolerance=1e-12, + phase_equal=False): """Check euler_angles_1q works for the given unitary""" target_unitary = operator.data if basis is None: @@ -92,7 +93,7 @@ def check_one_qubit_euler_angles(self, operator, basis=None, tolerance=1e-12): target_unitary *= la.det(target_unitary) ** (-0.5) decomp_unitary *= la.det(decomp_unitary) ** (-0.5) maxdist = np.max(np.abs(target_unitary - decomp_unitary)) - if maxdist > 0.1: + if not phase_equal and maxdist > 0.1: maxdist = np.max(np.abs(target_unitary + decomp_unitary)) self.assertTrue(np.abs(maxdist) < tolerance, "Operator {}: Worst distance {}".format(operator, maxdist)) From 62194efee39e7059b13554dd7374efb7a55427d5 Mon Sep 17 00:00:00 2001 From: Luciano Bello Date: Wed, 4 Mar 2020 18:14:34 -0500 Subject: [PATCH 34/49] loops out --- test/python/quantum_info/test_synthesis.py | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/test/python/quantum_info/test_synthesis.py b/test/python/quantum_info/test_synthesis.py index e62b93eac248..990086063ee5 100644 --- a/test/python/quantum_info/test_synthesis.py +++ b/test/python/quantum_info/test_synthesis.py @@ -139,15 +139,15 @@ def check_exact_decomposition(self, target_unitary, decomposer, tolerance=1.e-7) class TestEulerAngles1Q(CheckDecompositions): """Test euler_angles_1q()""" - def test_euler_angles_1q_clifford(self): + @combine(clifford=ONEQ_CLIFFORDS) + def test_euler_angles_1q_clifford(self, clifford): """Verify euler_angles_1q produces correct Euler angles for all Cliffords.""" - for clifford in ONEQ_CLIFFORDS: - self.check_one_qubit_euler_angles(clifford) + self.check_one_qubit_euler_angles(clifford) - def test_euler_angles_1q_hard_thetas(self): + @combine(gate=HARD_THETA_ONEQS) + def test_euler_angles_1q_hard_thetas(self, gate): """Verify euler_angles_1q for close-to-degenerate theta""" - for gate in HARD_THETA_ONEQS: - self.check_one_qubit_euler_angles(Operator(gate)) + self.check_one_qubit_euler_angles(Operator(gate)) @combine(seed=range(5), name='test_euler_angles_1q_random_{seed}') def test_euler_angles_1q_random(self, seed): From a0ec3d77762960e9ebc7be58be1b4f05501863c3 Mon Sep 17 00:00:00 2001 From: Luciano Bello Date: Thu, 7 May 2020 14:11:57 -0400 Subject: [PATCH 35/49] Update test/python/quantum_info/test_synthesis.py Co-authored-by: Ali Javadi-Abhari --- test/python/quantum_info/test_synthesis.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/python/quantum_info/test_synthesis.py b/test/python/quantum_info/test_synthesis.py index 3028280fac30..0d57341e002b 100644 --- a/test/python/quantum_info/test_synthesis.py +++ b/test/python/quantum_info/test_synthesis.py @@ -474,7 +474,7 @@ def test_exact_nonsupercontrolled_decompose(self): def test_cx_equivalence_0cx(self, seed=0): """Check circuits with 0 cx gates locally equivalent to identity """ - state = np.random.RandomState(seed) + state = np.random.default_rng(seed) rnd = 2 * np.pi * state.random(size=6) qr = QuantumRegister(2, name='q') From d09b04063ee1a05788aafff65dd6817c901ec027 Mon Sep 17 00:00:00 2001 From: Luciano Bello Date: Fri, 19 Jun 2020 16:55:39 -0400 Subject: [PATCH 36/49] other change --- test/python/quantum_info/test_synthesis.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/python/quantum_info/test_synthesis.py b/test/python/quantum_info/test_synthesis.py index 0139028efe37..69e2adc3745e 100644 --- a/test/python/quantum_info/test_synthesis.py +++ b/test/python/quantum_info/test_synthesis.py @@ -474,7 +474,7 @@ def test_exact_nonsupercontrolled_decompose(self): def test_cx_equivalence_0cx(self, seed=0): """Check circuits with 0 cx gates locally equivalent to identity """ - state = np.random.default_rng(seed) + state = np.random.RandomState(seed) rnd = 2 * np.pi * state.random(size=6) qr = QuantumRegister(2, name='q') From 0d751f8472965c04b07471c17d571bd79af7814b Mon Sep 17 00:00:00 2001 From: Luciano Bello Date: Sat, 20 Jun 2020 20:36:39 -0400 Subject: [PATCH 37/49] np.random.RandomState->np.random.default_rng --- test/python/quantum_info/test_synthesis.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/test/python/quantum_info/test_synthesis.py b/test/python/quantum_info/test_synthesis.py index 69e2adc3745e..a0911c9e8b47 100644 --- a/test/python/quantum_info/test_synthesis.py +++ b/test/python/quantum_info/test_synthesis.py @@ -474,7 +474,7 @@ def test_exact_nonsupercontrolled_decompose(self): def test_cx_equivalence_0cx(self, seed=0): """Check circuits with 0 cx gates locally equivalent to identity """ - state = np.random.RandomState(seed) + state = np.random.default_rng(seed) rnd = 2 * np.pi * state.random(size=6) qr = QuantumRegister(2, name='q') @@ -490,7 +490,7 @@ def test_cx_equivalence_0cx(self, seed=0): def test_cx_equivalence_1cx(self, seed=1): """Check circuits with 1 cx gates locally equivalent to a cx """ - state = np.random.RandomState(seed) + state = np.random.default_rng(seed) rnd = 2 * np.pi * state.random(size=12) qr = QuantumRegister(2, name='q') @@ -511,7 +511,7 @@ def test_cx_equivalence_1cx(self, seed=1): 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.RandomState(seed) + state = np.random.default_rng(seed) rnd = 2 * np.pi * state.random(size=18) qr = QuantumRegister(2, name='q') @@ -537,7 +537,7 @@ def test_cx_equivalence_2cx(self, seed=2): 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.RandomState(seed) + state = np.random.default_rng(seed) rnd = 2 * np.pi * state.random(size=24) qr = QuantumRegister(2, name='q') From 7c68be81c71c80ae9b45e14611fe0322607ce453 Mon Sep 17 00:00:00 2001 From: Luciano Bello Date: Fri, 14 Aug 2020 18:46:24 -0400 Subject: [PATCH 38/49] Update test/python/quantum_info/test_synthesis.py Co-authored-by: Kevin Krsulich --- test/python/quantum_info/test_synthesis.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/python/quantum_info/test_synthesis.py b/test/python/quantum_info/test_synthesis.py index da4c9399331c..2d3745a48ae0 100644 --- a/test/python/quantum_info/test_synthesis.py +++ b/test/python/quantum_info/test_synthesis.py @@ -79,7 +79,7 @@ def make_hard_thetas_oneq(smallest=1e-18, factor=3.2, steps=22, phi=0.7, lam=0.9 class CheckDecompositions(QiskitTestCase): """Implements decomposition checkers.""" - def check_one_qubit_euler_angles(self, operator, basis=None, tolerance=1e-12, + def check_one_qubit_euler_angles(self, operator, basis='U3', tolerance=1e-12, phase_equal=False): """Check euler_angles_1q works for the given unitary""" target_unitary = operator.data From 7a703dda411bcd4c6f908c53e77075fa17ddd06a Mon Sep 17 00:00:00 2001 From: Luciano Bello Date: Fri, 14 Aug 2020 18:49:19 -0400 Subject: [PATCH 39/49] OneQubitEulerDecomposer --- test/python/quantum_info/test_synthesis.py | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/test/python/quantum_info/test_synthesis.py b/test/python/quantum_info/test_synthesis.py index da4c9399331c..f80b429600c1 100644 --- a/test/python/quantum_info/test_synthesis.py +++ b/test/python/quantum_info/test_synthesis.py @@ -32,8 +32,7 @@ from qiskit.quantum_info.synthesis.two_qubit_decompose import (TwoQubitWeylDecomposition, two_qubit_cnot_decompose, TwoQubitBasisDecomposer, - Ud, - euler_angles_1q) + Ud) from qiskit.quantum_info.synthesis.ion_decompose import cnot_rxx_decompose from qiskit.test import QiskitTestCase @@ -81,10 +80,10 @@ class CheckDecompositions(QiskitTestCase): def check_one_qubit_euler_angles(self, operator, basis=None, tolerance=1e-12, phase_equal=False): - """Check euler_angles_1q works for the given unitary""" + """Check OneQubitEulerDecomposer works for the given unitary""" target_unitary = operator.data if basis is None: - angles = euler_angles_1q(target_unitary) + angles = OneQubitEulerDecomposer().angles(target_unitary) decomp_unitary = U3Gate(*angles).to_matrix() else: decomposer = OneQubitEulerDecomposer(basis) From 3b6d4ccdcc0c71de53777d36a83c9676fa31b62c Mon Sep 17 00:00:00 2001 From: Luciano Bello Date: Fri, 14 Aug 2020 19:30:48 -0400 Subject: [PATCH 40/49] seed as given --- test/randomized/test_synthesis.py | 25 +++++++++++++------------ 1 file changed, 13 insertions(+), 12 deletions(-) diff --git a/test/randomized/test_synthesis.py b/test/randomized/test_synthesis.py index 92d8ec7bef22..df208df9c5c8 100644 --- a/test/randomized/test_synthesis.py +++ b/test/randomized/test_synthesis.py @@ -63,9 +63,10 @@ def test_exact_supercontrolled_decompose_random(self, seeds): self.check_exact_decomposition(random_unitary(4, seed=seeds[4]).data, decomposer) rotation = strategies.floats(min_value=-np.pi*10, max_value=np.pi*10) + seed = strategies.integers(min_value=0, max_value=2 ** 32 - 1) - @given(strategies.tuples(*[rotation] * 6)) - def test_cx_equivalence_0cx_random(self, rnd): + @given(strategies.tuples(*[rotation] * 6), seed) + def test_cx_equivalence_0cx_random(self, rnd, seed): """Check random circuits with 0 cx gates locally equivalent to identity. """ qr = QuantumRegister(2, name='q') @@ -75,11 +76,11 @@ def test_cx_equivalence_0cx_random(self, rnd): qc.u3(rnd[3], rnd[4], rnd[5], qr[1]) sim = UnitarySimulatorPy() - unitary = execute(qc, sim).result().get_unitary() + unitary = execute(qc, sim, seed_simulator=seed).result().get_unitary() self.assertEqual(two_qubit_cnot_decompose.num_basis_gates(unitary), 0) - @given(strategies.tuples(*[rotation] * 12)) - def test_cx_equivalence_1cx_random(self, rnd): + @given(strategies.tuples(*[rotation] * 12), seed) + def test_cx_equivalence_1cx_random(self, rnd, seed): """Check random circuits with 1 cx gates locally equivalent to a cx. """ qr = QuantumRegister(2, name='q') @@ -94,11 +95,11 @@ def test_cx_equivalence_1cx_random(self, rnd): qc.u3(rnd[9], rnd[10], rnd[11], qr[1]) sim = UnitarySimulatorPy() - unitary = execute(qc, sim).result().get_unitary() + unitary = execute(qc, sim, seed_simulator=seed).result().get_unitary() self.assertEqual(two_qubit_cnot_decompose.num_basis_gates(unitary), 1) - @given(strategies.tuples(*[rotation] * 18)) - def test_cx_equivalence_2cx_random(self, rnd): + @given(strategies.tuples(*[rotation] * 18), seed) + def test_cx_equivalence_2cx_random(self, rnd, seed): """Check random circuits with 2 cx gates locally equivalent to some circuit with 2 cx. """ qr = QuantumRegister(2, name='q') @@ -118,11 +119,11 @@ def test_cx_equivalence_2cx_random(self, rnd): qc.u3(rnd[15], rnd[16], rnd[17], qr[1]) sim = UnitarySimulatorPy() - unitary = execute(qc, sim).result().get_unitary() + unitary = execute(qc, sim, seed_simulator=seed).result().get_unitary() self.assertEqual(two_qubit_cnot_decompose.num_basis_gates(unitary), 2) - @given(strategies.tuples(*[rotation] * 24)) - def test_cx_equivalence_3cx_random(self, rnd): + @given(strategies.tuples(*[rotation] * 24), seed) + def test_cx_equivalence_3cx_random(self, rnd, seed): """Check random circuits with 3 cx gates are outside the 0, 1, and 2 qubit regions. """ qr = QuantumRegister(2, name='q') @@ -147,7 +148,7 @@ def test_cx_equivalence_3cx_random(self, rnd): qc.u3(rnd[21], rnd[22], rnd[23], qr[1]) sim = UnitarySimulatorPy() - unitary = execute(qc, sim).result().get_unitary() + unitary = execute(qc, sim, seed_simulator=seed).result().get_unitary() self.assertEqual(two_qubit_cnot_decompose.num_basis_gates(unitary), 3) From 8519ffc8211feadf88609985a832f1e0c3c6e669 Mon Sep 17 00:00:00 2001 From: Luciano Bello Date: Tue, 18 Aug 2020 14:37:59 -0400 Subject: [PATCH 41/49] Update test/randomized/test_synthesis.py Co-authored-by: Kevin Krsulich --- test/randomized/test_synthesis.py | 1 + 1 file changed, 1 insertion(+) diff --git a/test/randomized/test_synthesis.py b/test/randomized/test_synthesis.py index df208df9c5c8..bb8dde36f7dd 100644 --- a/test/randomized/test_synthesis.py +++ b/test/randomized/test_synthesis.py @@ -41,6 +41,7 @@ def test_1q_random(self, seed): self.check_one_qubit_euler_angles(unitary, 'ZYZ') self.check_one_qubit_euler_angles(unitary, 'ZXZ') self.check_one_qubit_euler_angles(unitary, 'XYX') + self.check_one_qubit_euler_angles(unitary, 'RR') @given(strategies.integers(min_value=0, max_value=2 ** 32 - 1)) def test_2q_random(self, seed): From 0fb6ea7069291722339e817bd2e65f1b3df0e2b0 Mon Sep 17 00:00:00 2001 From: Luciano Bello Date: Tue, 18 Aug 2020 15:04:28 -0400 Subject: [PATCH 42/49] condesing --- test/python/quantum_info/test_synthesis.py | 69 ++++++---------------- 1 file changed, 19 insertions(+), 50 deletions(-) diff --git a/test/python/quantum_info/test_synthesis.py b/test/python/quantum_info/test_synthesis.py index 31ad49897606..a25d3b8ca1aa 100644 --- a/test/python/quantum_info/test_synthesis.py +++ b/test/python/quantum_info/test_synthesis.py @@ -159,6 +159,7 @@ def test_euler_angles_1q_random(self, seed): @ddt class TestOneQubitEulerDecomposer(CheckDecompositions): """Test OneQubitEulerDecomposer""" + def check_one_qubit_euler_angles(self, operator, basis='U3', tolerance=1e-12, phase_equal=False): @@ -192,18 +193,20 @@ def test_one_qubit_clifford_u1x_basis(self): for clifford in ONEQ_CLIFFORDS: self.check_one_qubit_euler_angles(clifford, 'U1X') - def test_one_qubit_hard_thetas_u1x_basis(self): - """Verify for u1, x90 basis and close-to-degenerate theta.""" - # We lower tolerance for this test since decomposition is - # less numerically accurate. This is due to it having 5 matrix - # multiplications and the X90 gates + @combine(basis_tolerance=[('XYX', 1e-12), ('ZYZ', 1e-12), ('U1X', 1e-7)], + name='test_one_qubit_hard_thetas_{basis_tolerance[0]}_basis') + def test_one_qubit_hard_thetas_basis(self, basis_tolerance): + """Verify for {basis_tolerance[0]} basis and close-to-degenerate theta.""" for gate in HARD_THETA_ONEQS: - self.check_one_qubit_euler_angles(Operator(gate), 'U1X', 1e-7) + self.check_one_qubit_euler_angles(Operator(gate), basis_tolerance[0], + basis_tolerance[1]) - def test_one_qubit_hard_thetas_zyz_basis(self): - """Verify for rz, ry, rz basis and close-to-degenerate theta.""" - for gate in HARD_THETA_ONEQS: - self.check_one_qubit_euler_angles(Operator(gate), 'ZYZ', 1e-12) + @combine(basis=['U3', 'U1X', 'ZYZ', 'ZXZ', 'XYX', 'RR'], seed=range(50), + name='test_one_qubit_random_{basis}_basis_{seed}') + def test_one_qubit_random_rr_basis(self, basis, seed): + """Verify for {basis} basis and random_unitary (seed={seed}).""" + unitary = random_unitary(2, seed=seed) + self.check_one_qubit_euler_angles(unitary, basis) # Rz, Ry, Rz basis def test_one_qubit_clifford_zyz_basis(self): @@ -228,41 +231,6 @@ def test_one_qubit_clifford_xyx_basis(self): for clifford in ONEQ_CLIFFORDS: self.check_one_qubit_euler_angles(clifford, 'XYX') - def test_one_qubit_hard_thetas_xyx_basis(self): - """Verify for rx, ry, rx basis and close-to-degenerate theta.""" - for gate in HARD_THETA_ONEQS: - self.check_one_qubit_euler_angles(Operator(gate), 'XYX') - - @combine(seed=range(50), name='test_one_qubit_random_u3_basis_{seed}') - def test_one_qubit_random_u3_basis(self, seed): - """Verify for u3 basis and random_unitary (seed={seed}).""" - unitary = random_unitary(2, seed=seed) - self.check_one_qubit_euler_angles(unitary, 'U3') - - @combine(seed=range(50), name='test_one_qubit_random_u1x_basis_{seed}') - def test_one_qubit_random_u1x_basis(self, seed): - """Verify for u1, x90 basis and random_unitary (seed={seed}).""" - unitary = random_unitary(2, seed=seed) - self.check_one_qubit_euler_angles(unitary, 'U1X') - - @combine(seed=range(50), name='test_one_qubit_random_zyz_basis_{seed}') - def test_one_qubit_random_zyz_basis(self, seed): - """Verify for rz, ry, rz basis and random_unitary (seed={seed}).""" - unitary = random_unitary(2, seed=seed) - self.check_one_qubit_euler_angles(unitary, 'ZYZ') - - @combine(seed=range(50), name='test_one_qubit_random_zxz_basis_{seed}') - def test_one_qubit_random_zxz_basis(self, seed): - """Verify for rz, rx, rz basis and random_unitary (seed={seed}).""" - unitary = random_unitary(2, seed=seed) - self.check_one_qubit_euler_angles(unitary, 'ZXZ') - - @combine(seed=range(50), name='test_one_qubit_random_xyx_basis_{seed}') - def test_one_qubit_random_xyx_basis(self, seed): - """Verify for rx, ry, rx basis and random_unitary (seed={seed}).""" - unitary = random_unitary(2, seed=seed) - self.check_one_qubit_euler_angles(unitary, 'XYX') - # R, R basis def test_one_qubit_clifford_rr_basis(self): """Verify for r, r basis and all Cliffords.""" @@ -430,10 +398,10 @@ def test_random_unitary_fp_precision_error(self): gate = CXGate() self.check_two_qubit_weyl_decomposition(Operator(gate).data) decomp = TwoQubitWeylDecomposition(Operator(gate).data) - expected_k1r = np.array([[-0.5+0.5j, -0.5+0.5j], - [0.5+0.5j, -0.5-0.5j]]) - expected_k2l = np.array([[0.0+0.0j, -1.0+0.0j], - [1.0+0.0j, 0.0+0.0j]]) + expected_k1r = np.array([[-0.5 + 0.5j, -0.5 + 0.5j], + [0.5 + 0.5j, -0.5 - 0.5j]]) + expected_k2l = np.array([[0.0 + 0.0j, -1.0 + 0.0j], + [1.0 + 0.0j, 0.0 + 0.0j]]) sqrt_2 = 1 / np.sqrt(2) expected_k2r = np.array([[complex(0, sqrt_2), complex(0, sqrt_2)], [complex(0, sqrt_2), complex(0, -sqrt_2)]]) @@ -611,7 +579,7 @@ def test_seed_289(self): 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')], + (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.""" @@ -628,6 +596,7 @@ def test_euler_basis_selection(self, euler_bases, kak_gates, seed): self.assertTrue( decomposition_basis.issubset(requested_basis)) + # FIXME: need to write tests for the approximate decompositions From 8bd2854108054040ab337c8513a83b0564c9e5ac Mon Sep 17 00:00:00 2001 From: Luciano Bello Date: Tue, 18 Aug 2020 15:13:54 -0400 Subject: [PATCH 43/49] test_one_qubit_clifford_all_basis --- test/python/quantum_info/test_synthesis.py | 63 +++++----------------- 1 file changed, 12 insertions(+), 51 deletions(-) diff --git a/test/python/quantum_info/test_synthesis.py b/test/python/quantum_info/test_synthesis.py index a25d3b8ca1aa..fb2ea1b297c0 100644 --- a/test/python/quantum_info/test_synthesis.py +++ b/test/python/quantum_info/test_synthesis.py @@ -176,24 +176,19 @@ def check_one_qubit_euler_angles(self, operator, basis='U3', maxdist = np.max(np.abs(target_unitary + decomp_unitary)) self.assertTrue(np.abs(maxdist) < tolerance, "Worst distance {}".format(maxdist)) - # U3 basis - def test_one_qubit_clifford_u3_basis(self): - """Verify for u3 basis and all Cliffords.""" + @combine(basis=['U3', 'U1X', 'ZYZ', 'ZXZ', 'XYX', 'RR'], + name='test_one_qubit_clifford_{basis}_basis') + def test_one_qubit_clifford_all_basis(self, basis): + """Verify for {basis} basis and all Cliffords.""" for clifford in ONEQ_CLIFFORDS: - self.check_one_qubit_euler_angles(clifford, 'U3') - - def test_one_qubit_hard_thetas_u3_basis(self): - """Verify for u3 basis and close-to-degenerate theta.""" - for gate in HARD_THETA_ONEQS: - self.check_one_qubit_euler_angles(Operator(gate), 'U3') - - # U1, X90 basis - def test_one_qubit_clifford_u1x_basis(self): - """Verify for u1, x90 basis and all Cliffords.""" - for clifford in ONEQ_CLIFFORDS: - self.check_one_qubit_euler_angles(clifford, 'U1X') - - @combine(basis_tolerance=[('XYX', 1e-12), ('ZYZ', 1e-12), ('U1X', 1e-7)], + self.check_one_qubit_euler_angles(clifford, basis) + + @combine(basis_tolerance=[('U3', 1e-12), + ('XYX', 1e-12), + ('ZXZ', 1e-12), + ('ZYZ', 1e-12) + ('U1X', 1e-7), + ('RR', 1e-12)], name='test_one_qubit_hard_thetas_{basis_tolerance[0]}_basis') def test_one_qubit_hard_thetas_basis(self, basis_tolerance): """Verify for {basis_tolerance[0]} basis and close-to-degenerate theta.""" @@ -208,40 +203,6 @@ def test_one_qubit_random_rr_basis(self, basis, seed): unitary = random_unitary(2, seed=seed) self.check_one_qubit_euler_angles(unitary, basis) - # Rz, Ry, Rz basis - def test_one_qubit_clifford_zyz_basis(self): - """Verify for rz, ry, rz basis and all Cliffords.""" - for clifford in ONEQ_CLIFFORDS: - self.check_one_qubit_euler_angles(clifford, 'ZYZ') - - # Rz, Rx, Rz basis - def test_one_qubit_clifford_zxz_basis(self): - """Verify for rz, rx, rz basis and all Cliffords.""" - for clifford in ONEQ_CLIFFORDS: - self.check_one_qubit_euler_angles(clifford, 'ZXZ') - - def test_one_qubit_hard_thetas_zxz_basis(self): - """Verify for rz, rx, rz basis and close-to-degenerate theta.""" - for gate in HARD_THETA_ONEQS: - self.check_one_qubit_euler_angles(Operator(gate), 'ZXZ', 1e-12) - - # Rx, Ry, Rx basis - def test_one_qubit_clifford_xyx_basis(self): - """Verify for rx, ry, rx basis and all Cliffords.""" - for clifford in ONEQ_CLIFFORDS: - self.check_one_qubit_euler_angles(clifford, 'XYX') - - # R, R basis - def test_one_qubit_clifford_rr_basis(self): - """Verify for r, r basis and all Cliffords.""" - for clifford in ONEQ_CLIFFORDS: - self.check_one_qubit_euler_angles(clifford, 'RR') - - def test_one_qubit_hard_thetas_rr_basis(self): - """Verify for r, r basis and close-to-degenerate theta.""" - for gate in HARD_THETA_ONEQS: - self.check_one_qubit_euler_angles(Operator(gate), 'RR') - def test_one_qubit_random_rr_basis(self, nsamples=50): """Verify for r, r basis and random unitaries.""" for _ in range(nsamples): From b13ca05270c817ec51230a537709761869d9620c Mon Sep 17 00:00:00 2001 From: Luciano Bello Date: Tue, 18 Aug 2020 16:18:44 -0400 Subject: [PATCH 44/49] repeated --- test/python/quantum_info/test_synthesis.py | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) diff --git a/test/python/quantum_info/test_synthesis.py b/test/python/quantum_info/test_synthesis.py index fb2ea1b297c0..3245f0c86a38 100644 --- a/test/python/quantum_info/test_synthesis.py +++ b/test/python/quantum_info/test_synthesis.py @@ -190,7 +190,7 @@ def test_one_qubit_clifford_all_basis(self, basis): ('U1X', 1e-7), ('RR', 1e-12)], name='test_one_qubit_hard_thetas_{basis_tolerance[0]}_basis') - def test_one_qubit_hard_thetas_basis(self, basis_tolerance): + def test_one_qubit_hard_thetas_all_basis(self, basis_tolerance): """Verify for {basis_tolerance[0]} basis and close-to-degenerate theta.""" for gate in HARD_THETA_ONEQS: self.check_one_qubit_euler_angles(Operator(gate), basis_tolerance[0], @@ -198,17 +198,11 @@ def test_one_qubit_hard_thetas_basis(self, basis_tolerance): @combine(basis=['U3', 'U1X', 'ZYZ', 'ZXZ', 'XYX', 'RR'], seed=range(50), name='test_one_qubit_random_{basis}_basis_{seed}') - def test_one_qubit_random_rr_basis(self, basis, seed): + def test_one_qubit_random_all_basis(self, basis, seed): """Verify for {basis} basis and random_unitary (seed={seed}).""" unitary = random_unitary(2, seed=seed) self.check_one_qubit_euler_angles(unitary, basis) - def test_one_qubit_random_rr_basis(self, nsamples=50): - """Verify for r, r basis and random unitaries.""" - for _ in range(nsamples): - unitary = random_unitary(2) - self.check_one_qubit_euler_angles(unitary, 'RR') - # FIXME: streamline the set of test cases class TestTwoQubitWeylDecomposition(CheckDecompositions): From 7b9e84142b0b64dc4e18bb070815f4e7f45dcc27 Mon Sep 17 00:00:00 2001 From: Luciano Bello Date: Tue, 18 Aug 2020 16:55:15 -0400 Subject: [PATCH 45/49] tuple --- test/python/quantum_info/test_synthesis.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/python/quantum_info/test_synthesis.py b/test/python/quantum_info/test_synthesis.py index 3245f0c86a38..f586eafe4401 100644 --- a/test/python/quantum_info/test_synthesis.py +++ b/test/python/quantum_info/test_synthesis.py @@ -186,7 +186,7 @@ def test_one_qubit_clifford_all_basis(self, basis): @combine(basis_tolerance=[('U3', 1e-12), ('XYX', 1e-12), ('ZXZ', 1e-12), - ('ZYZ', 1e-12) + ('ZYZ', 1e-12), ('U1X', 1e-7), ('RR', 1e-12)], name='test_one_qubit_hard_thetas_{basis_tolerance[0]}_basis') From 904c23c43cbdc174fbe0832a65b93975ec169265 Mon Sep 17 00:00:00 2001 From: Luciano Bello Date: Tue, 18 Aug 2020 17:27:43 -0400 Subject: [PATCH 46/49] strategies --- test/randomized/test_synthesis.py | 16 ++++++---------- 1 file changed, 6 insertions(+), 10 deletions(-) diff --git a/test/randomized/test_synthesis.py b/test/randomized/test_synthesis.py index bb8dde36f7dd..76096e0e5650 100644 --- a/test/randomized/test_synthesis.py +++ b/test/randomized/test_synthesis.py @@ -31,7 +31,10 @@ class TestSynthesis(CheckDecompositions): """Test synthesis""" - @given(strategies.integers(min_value=0, max_value=2 ** 32 - 1)) + seed = strategies.integers(min_value=0, max_value=2 ** 32 - 1) + rotation = strategies.floats(min_value=-np.pi*10, max_value=np.pi*10) + + @given(seed) def test_1q_random(self, seed): """Checks one qubit decompositions""" unitary = random_unitary(2, seed=seed) @@ -43,17 +46,13 @@ def test_1q_random(self, seed): self.check_one_qubit_euler_angles(unitary, 'XYX') self.check_one_qubit_euler_angles(unitary, 'RR') - @given(strategies.integers(min_value=0, max_value=2 ** 32 - 1)) + @given(seed) def test_2q_random(self, seed): """Checks two qubit decompositions""" unitary = random_unitary(4, seed=seed) self.check_exact_decomposition(unitary.data, two_qubit_cnot_decompose) - @given(strategies.tuples(strategies.integers(min_value=0, max_value=2 ** 32 - 1), - strategies.integers(min_value=0, max_value=2 ** 32 - 1), - strategies.integers(min_value=0, max_value=2 ** 32 - 1), - strategies.integers(min_value=0, max_value=2 ** 32 - 1), - strategies.integers(min_value=0, max_value=2 ** 32 - 1))) + @given(strategies.tuples(*[seed] * 5)) def test_exact_supercontrolled_decompose_random(self, seeds): """Exact decomposition for random supercontrolled basis and random target""" # pylint: disable=invalid-name @@ -63,9 +62,6 @@ def test_exact_supercontrolled_decompose_random(self, seeds): decomposer = TwoQubitBasisDecomposer(UnitaryGate(basis_unitary)) self.check_exact_decomposition(random_unitary(4, seed=seeds[4]).data, decomposer) - rotation = strategies.floats(min_value=-np.pi*10, max_value=np.pi*10) - seed = strategies.integers(min_value=0, max_value=2 ** 32 - 1) - @given(strategies.tuples(*[rotation] * 6), seed) def test_cx_equivalence_0cx_random(self, rnd, seed): """Check random circuits with 0 cx gates locally equivalent to identity. From 6209132d4e108345355687de25377f4a61060618 Mon Sep 17 00:00:00 2001 From: Luciano Bello Date: Tue, 18 Aug 2020 17:32:09 -0400 Subject: [PATCH 47/49] comment --- test/python/quantum_info/test_synthesis.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/test/python/quantum_info/test_synthesis.py b/test/python/quantum_info/test_synthesis.py index f586eafe4401..9ff09e243990 100644 --- a/test/python/quantum_info/test_synthesis.py +++ b/test/python/quantum_info/test_synthesis.py @@ -190,6 +190,9 @@ def test_one_qubit_clifford_all_basis(self, basis): ('U1X', 1e-7), ('RR', 1e-12)], name='test_one_qubit_hard_thetas_{basis_tolerance[0]}_basis') + # Lower tolerance for U1X test since decomposition since it is + # less numerically accurate. This is due to it having 5 matrix + # multiplications and the X90 gates def test_one_qubit_hard_thetas_all_basis(self, basis_tolerance): """Verify for {basis_tolerance[0]} basis and close-to-degenerate theta.""" for gate in HARD_THETA_ONEQS: From dbb368bb12b50ae506bea55a4ad33130bc8b5019 Mon Sep 17 00:00:00 2001 From: Luciano Bello Date: Tue, 18 Aug 2020 20:23:32 -0400 Subject: [PATCH 48/49] self.assertTrue(Operator(two_qubit_cnot_decompose).equiv(unitary)) --- test/python/quantum_info/test_synthesis.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/test/python/quantum_info/test_synthesis.py b/test/python/quantum_info/test_synthesis.py index 9ff09e243990..b27e3284dd60 100644 --- a/test/python/quantum_info/test_synthesis.py +++ b/test/python/quantum_info/test_synthesis.py @@ -448,6 +448,7 @@ def test_cx_equivalence_0cx(self, seed=0): 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).equiv(unitary)) def test_cx_equivalence_1cx(self, seed=1): """Check circuits with 1 cx gates locally equivalent to a cx @@ -469,6 +470,7 @@ def test_cx_equivalence_1cx(self, seed=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).equiv(unitary)) def test_cx_equivalence_2cx(self, seed=2): """Check circuits with 2 cx gates locally equivalent to some circuit with 2 cx. @@ -495,6 +497,7 @@ def test_cx_equivalence_2cx(self, seed=2): 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).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. @@ -526,6 +529,7 @@ def test_cx_equivalence_3cx(self, seed=3): 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).equiv(unitary)) def test_seed_289(self): """This specific case failed when PR #3585 was applied From 54056d7db52e4ffd72c8ab6a7c2435a4c3430392 Mon Sep 17 00:00:00 2001 From: Luciano Bello Date: Wed, 19 Aug 2020 16:04:29 -0400 Subject: [PATCH 49/49] bugfix --- test/python/quantum_info/test_synthesis.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/test/python/quantum_info/test_synthesis.py b/test/python/quantum_info/test_synthesis.py index b27e3284dd60..b1c3dc3cba4d 100644 --- a/test/python/quantum_info/test_synthesis.py +++ b/test/python/quantum_info/test_synthesis.py @@ -448,7 +448,7 @@ def test_cx_equivalence_0cx(self, seed=0): 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).equiv(unitary)) + 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 @@ -470,7 +470,7 @@ def test_cx_equivalence_1cx(self, seed=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).equiv(unitary)) + 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. @@ -497,7 +497,7 @@ def test_cx_equivalence_2cx(self, seed=2): 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).equiv(unitary)) + 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. @@ -529,7 +529,7 @@ def test_cx_equivalence_3cx(self, seed=3): 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).equiv(unitary)) + self.assertTrue(Operator(two_qubit_cnot_decompose(unitary)).equiv(unitary)) def test_seed_289(self): """This specific case failed when PR #3585 was applied