From aabb4f0ac8937b107df0d56250ea419a35f0460f Mon Sep 17 00:00:00 2001 From: Harshit Gupta Date: Wed, 19 Jan 2022 18:37:06 +0530 Subject: [PATCH 1/8] add fixed point for size --- qiskit/transpiler/preset_passmanagers/level2.py | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/qiskit/transpiler/preset_passmanagers/level2.py b/qiskit/transpiler/preset_passmanagers/level2.py index 1120db671468..8fb6138c16d3 100644 --- a/qiskit/transpiler/preset_passmanagers/level2.py +++ b/qiskit/transpiler/preset_passmanagers/level2.py @@ -41,6 +41,7 @@ from qiskit.transpiler.passes import EnlargeWithAncilla from qiskit.transpiler.passes import FixedPoint from qiskit.transpiler.passes import Depth +from qiskit.transpiler.passes import Size from qiskit.transpiler.passes import RemoveResetInZeroState from qiskit.transpiler.passes import Optimize1qGatesDecomposition from qiskit.transpiler.passes import CommutativeCancellation @@ -268,11 +269,16 @@ def _direction_condition(property_set): _reset = RemoveResetInZeroState() # 8. 1q rotation merge and commutative cancellation iteratively until no more change in depth + # and size _depth_check = [Depth(), FixedPoint("depth")] + _size_check = [Size(), FixedPoint("size")] - def _opt_control(property_set): + def _depth_control(property_set): return not property_set["depth_fixed_point"] + def _size_control(property_set): + return not property_set["size_fixed_point"] + _opt = [ Optimize1qGatesDecomposition(basis_gates), CommutativeCancellation(basis_gates=basis_gates), @@ -329,7 +335,10 @@ def _contains_delay(property_set): pm2.append(_direction_check) pm2.append(_direction, condition=_direction_condition) pm2.append(_reset) - pm2.append(_depth_check + _opt + _unroll, do_while=_opt_control) + + pm2.append(_depth_check + _opt + _unroll, do_while=_depth_control) + pm2.append(_size_check + _opt + _unroll, do_while=_size_control) + if inst_map and inst_map.has_custom_gate(): pm2.append(PulseGates(inst_map=inst_map)) if scheduling_method: From 26461acb89511196a9485b2e2d18d02d8aa5dfed Mon Sep 17 00:00:00 2001 From: Harshit Gupta Date: Thu, 20 Jan 2022 12:05:08 +0530 Subject: [PATCH 2/8] change opt for all levels --- qiskit/transpiler/preset_passmanagers/level1.py | 7 +++++-- qiskit/transpiler/preset_passmanagers/level2.py | 10 +++------- qiskit/transpiler/preset_passmanagers/level3.py | 12 ++++++++---- 3 files changed, 16 insertions(+), 13 deletions(-) diff --git a/qiskit/transpiler/preset_passmanagers/level1.py b/qiskit/transpiler/preset_passmanagers/level1.py index 1db056c15244..25db065db79a 100644 --- a/qiskit/transpiler/preset_passmanagers/level1.py +++ b/qiskit/transpiler/preset_passmanagers/level1.py @@ -40,6 +40,7 @@ from qiskit.transpiler.passes import EnlargeWithAncilla from qiskit.transpiler.passes import FixedPoint from qiskit.transpiler.passes import Depth +from qiskit.transpiler.passes import Size from qiskit.transpiler.passes import RemoveResetInZeroState from qiskit.transpiler.passes import Optimize1qGatesDecomposition from qiskit.transpiler.passes import ApplyLayout @@ -234,10 +235,12 @@ def _direction_condition(property_set): _reset = RemoveResetInZeroState() # 9. Merge 1q rotations and cancel CNOT gates iteratively until no more change in depth + # or size _depth_check = [Depth(), FixedPoint("depth")] + _size_check = [Size(), FixedPoint("size")] def _opt_control(property_set): - return not property_set["depth_fixed_point"] + return (not property_set["depth_fixed_point"]) or (not property_set["size_fixed_point"]) _opt = [Optimize1qGatesDecomposition(basis_gates), CXCancellation()] @@ -291,7 +294,7 @@ def _contains_delay(property_set): pm1.append(_direction_check) pm1.append(_direction, condition=_direction_condition) pm1.append(_reset) - pm1.append(_depth_check + _opt + _unroll, do_while=_opt_control) + pm1.append(_depth_check + _size_check + _opt + _unroll, do_while=_opt_control) if inst_map and inst_map.has_custom_gate(): pm1.append(PulseGates(inst_map=inst_map)) if scheduling_method: diff --git a/qiskit/transpiler/preset_passmanagers/level2.py b/qiskit/transpiler/preset_passmanagers/level2.py index 8fb6138c16d3..7af5f8c67755 100644 --- a/qiskit/transpiler/preset_passmanagers/level2.py +++ b/qiskit/transpiler/preset_passmanagers/level2.py @@ -273,11 +273,8 @@ def _direction_condition(property_set): _depth_check = [Depth(), FixedPoint("depth")] _size_check = [Size(), FixedPoint("size")] - def _depth_control(property_set): - return not property_set["depth_fixed_point"] - - def _size_control(property_set): - return not property_set["size_fixed_point"] + def _opt_control(property_set): + return (not property_set["depth_fixed_point"]) or (not property_set["size_fixed_point"]) _opt = [ Optimize1qGatesDecomposition(basis_gates), @@ -336,8 +333,7 @@ def _contains_delay(property_set): pm2.append(_direction, condition=_direction_condition) pm2.append(_reset) - pm2.append(_depth_check + _opt + _unroll, do_while=_depth_control) - pm2.append(_size_check + _opt + _unroll, do_while=_size_control) + pm2.append(_depth_check + _size_check + _opt + _unroll, do_while=_opt_control) if inst_map and inst_map.has_custom_gate(): pm2.append(PulseGates(inst_map=inst_map)) diff --git a/qiskit/transpiler/preset_passmanagers/level3.py b/qiskit/transpiler/preset_passmanagers/level3.py index dab463e60202..8fa2384e560b 100644 --- a/qiskit/transpiler/preset_passmanagers/level3.py +++ b/qiskit/transpiler/preset_passmanagers/level3.py @@ -42,6 +42,7 @@ from qiskit.transpiler.passes import EnlargeWithAncilla from qiskit.transpiler.passes import FixedPoint from qiskit.transpiler.passes import Depth +from qiskit.transpiler.passes import Size from qiskit.transpiler.passes import RemoveResetInZeroState from qiskit.transpiler.passes import Optimize1qGatesDecomposition from qiskit.transpiler.passes import CommutativeCancellation @@ -266,9 +267,10 @@ def _direction_condition(property_set): # 8. Optimize iteratively until no more change in depth. Removes useless gates # after reset and before measure, commutes gates and optimizes contiguous blocks. _depth_check = [Depth(), FixedPoint("depth")] + _size_check = [Size(), FixedPoint("size")] def _opt_control(property_set): - return not property_set["depth_fixed_point"] + return (not property_set["depth_fixed_point"]) or (not property_set["size_fixed_point"]) _reset = [RemoveResetInZeroState()] @@ -346,12 +348,14 @@ def _contains_delay(property_set): # inserted by UnitarySynthesis which is direction aware but only via # the coupling map which with a target doesn't give a full picture if target is not None: - pm3.append(_depth_check + _opt + _unroll + _direction, do_while=_opt_control) + pm3.append( + _depth_check + _size_check + _opt + _unroll + _direction, do_while=_opt_control + ) else: - pm3.append(_depth_check + _opt + _unroll, do_while=_opt_control) + pm3.append(_depth_check + _size_check + _opt + _unroll, do_while=_opt_control) else: pm3.append(_reset) - pm3.append(_depth_check + _opt + _unroll, do_while=_opt_control) + pm3.append(_depth_check + _size_check + _opt + _unroll, do_while=_opt_control) if inst_map and inst_map.has_custom_gate(): pm3.append(PulseGates(inst_map=inst_map)) if scheduling_method: From 033908f44ba13cfca1051330b55e1d3f1b599b5e Mon Sep 17 00:00:00 2001 From: Harshit Gupta Date: Thu, 20 Jan 2022 14:49:22 +0530 Subject: [PATCH 3/8] restart tests --- qiskit/transpiler/preset_passmanagers/level1.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/qiskit/transpiler/preset_passmanagers/level1.py b/qiskit/transpiler/preset_passmanagers/level1.py index 25db065db79a..16c7ada0399f 100644 --- a/qiskit/transpiler/preset_passmanagers/level1.py +++ b/qiskit/transpiler/preset_passmanagers/level1.py @@ -235,7 +235,7 @@ def _direction_condition(property_set): _reset = RemoveResetInZeroState() # 9. Merge 1q rotations and cancel CNOT gates iteratively until no more change in depth - # or size + # or size of circuit _depth_check = [Depth(), FixedPoint("depth")] _size_check = [Size(), FixedPoint("size")] From 4e16fd72b38015e0901300d8ad5a280e6d2aecfb Mon Sep 17 00:00:00 2001 From: Harshit Gupta Date: Thu, 20 Jan 2022 18:42:47 +0530 Subject: [PATCH 4/8] add basic test --- .../transpiler/test_preset_passmanagers.py | 29 +++++++++++++++++++ 1 file changed, 29 insertions(+) diff --git a/test/python/transpiler/test_preset_passmanagers.py b/test/python/transpiler/test_preset_passmanagers.py index 62430edf6f34..e6b75e797b35 100644 --- a/test/python/transpiler/test_preset_passmanagers.py +++ b/test/python/transpiler/test_preset_passmanagers.py @@ -919,3 +919,32 @@ def test_input_dag_copy(self): qc.cx(1, 0) circ = transpile(qc, basis_gates=["u3", "cz"]) self.assertIsInstance(circ, QuantumCircuit) + + +@ddt +class TestOptimizationOnSize(QiskitTestCase): + """Test the optimization levels for optimization based on + both size and depth of the circuit. + See https://github.com/Qiskit/qiskit-terra/pull/7542 + """ + + @data(1, 2, 3) + def test_size_optimization(self, level): + """Test the levels for optimization based on size of circuit""" + qc = QuantumCircuit(8) + qc.cx(5, 4) + qc.cx(6, 5) + qc.cx(4, 5) + qc.cx(5, 6) + qc.cx(5, 4) + qc.cx(6, 7) + qc.cx(6, 5) + qc.cx(5, 4) + qc.cx(7, 6) + qc.cx(6, 7) + + circ = transpile(qc, optimization_level=level) + + self.assertIsInstance(circ, QuantumCircuit) + self.assertEqual(qc.size(), circ.size()) + self.assertEqual(qc.depth(), circ.depth()) From 06d597ac912d6ead8a1a29defb2326c6aeea08ae Mon Sep 17 00:00:00 2001 From: Harshit Gupta Date: Thu, 20 Jan 2022 18:55:42 +0530 Subject: [PATCH 5/8] add op check --- test/python/transpiler/test_preset_passmanagers.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/python/transpiler/test_preset_passmanagers.py b/test/python/transpiler/test_preset_passmanagers.py index e6b75e797b35..f923c8102f74 100644 --- a/test/python/transpiler/test_preset_passmanagers.py +++ b/test/python/transpiler/test_preset_passmanagers.py @@ -945,6 +945,6 @@ def test_size_optimization(self, level): circ = transpile(qc, optimization_level=level) - self.assertIsInstance(circ, QuantumCircuit) + self.assertDictEqual(qc.count_ops(), circ.count_ops()) self.assertEqual(qc.size(), circ.size()) self.assertEqual(qc.depth(), circ.depth()) From 3a67482e88954cb33e300053eb5175fb204e01fe Mon Sep 17 00:00:00 2001 From: Harshit Gupta Date: Sat, 22 Jan 2022 12:19:41 +0530 Subject: [PATCH 6/8] change test --- test/python/transpiler/test_preset_passmanagers.py | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/test/python/transpiler/test_preset_passmanagers.py b/test/python/transpiler/test_preset_passmanagers.py index f923c8102f74..409e1e60a1c1 100644 --- a/test/python/transpiler/test_preset_passmanagers.py +++ b/test/python/transpiler/test_preset_passmanagers.py @@ -928,15 +928,21 @@ class TestOptimizationOnSize(QiskitTestCase): See https://github.com/Qiskit/qiskit-terra/pull/7542 """ - @data(1, 2, 3) + @data(2, 3) def test_size_optimization(self, level): """Test the levels for optimization based on size of circuit""" qc = QuantumCircuit(8) + qc.cx(1, 2) + qc.cx(2, 3) qc.cx(5, 4) qc.cx(6, 5) qc.cx(4, 5) + qc.cx(3, 4) qc.cx(5, 6) qc.cx(5, 4) + qc.cx(3, 4) + qc.cx(2, 3) + qc.cx(1, 2) qc.cx(6, 7) qc.cx(6, 5) qc.cx(5, 4) @@ -945,6 +951,5 @@ def test_size_optimization(self, level): circ = transpile(qc, optimization_level=level) - self.assertDictEqual(qc.count_ops(), circ.count_ops()) - self.assertEqual(qc.size(), circ.size()) - self.assertEqual(qc.depth(), circ.depth()) + self.assertLessEqual(circ.size(), qc.size()) + self.assertLessEqual(circ.depth(), qc.depth()) From 49d94a2db82215643f602975238ffbf0cc913ecd Mon Sep 17 00:00:00 2001 From: Harshit Gupta Date: Tue, 15 Feb 2022 21:33:00 +0530 Subject: [PATCH 7/8] include qubit checks in test --- .../python/transpiler/test_preset_passmanagers.py | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/test/python/transpiler/test_preset_passmanagers.py b/test/python/transpiler/test_preset_passmanagers.py index 409e1e60a1c1..473bf945c081 100644 --- a/test/python/transpiler/test_preset_passmanagers.py +++ b/test/python/transpiler/test_preset_passmanagers.py @@ -949,7 +949,18 @@ def test_size_optimization(self, level): qc.cx(7, 6) qc.cx(6, 7) - circ = transpile(qc, optimization_level=level) + circ = transpile(qc, optimization_level=level).decompose() - self.assertLessEqual(circ.size(), qc.size()) + circ_data = circ.data + free_qubits = set([0, 1, 2, 3]) + + # ensure no gates are using qubits - (0,1,2,3) + for gate in circ_data: + qubits = gate[1] + indices = {circ.find_bit(qubit).index for qubit in qubits} + common = indices.intersection(free_qubits) + for common_qubit in common: + self.assertTrue(common_qubit not in free_qubits) + + self.assertLess(circ.size(), qc.size()) self.assertLessEqual(circ.depth(), qc.depth()) From f8fc1f32a3aaa62e1b12bb7b4c4db68a060f453b Mon Sep 17 00:00:00 2001 From: Harshit Gupta Date: Tue, 15 Feb 2022 23:00:07 +0530 Subject: [PATCH 8/8] restart test --- test/python/transpiler/test_preset_passmanagers.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/python/transpiler/test_preset_passmanagers.py b/test/python/transpiler/test_preset_passmanagers.py index 473bf945c081..ba08a10bfb48 100644 --- a/test/python/transpiler/test_preset_passmanagers.py +++ b/test/python/transpiler/test_preset_passmanagers.py @@ -954,7 +954,7 @@ def test_size_optimization(self, level): circ_data = circ.data free_qubits = set([0, 1, 2, 3]) - # ensure no gates are using qubits - (0,1,2,3) + # ensure no gates are using qubits - [0,1,2,3] for gate in circ_data: qubits = gate[1] indices = {circ.find_bit(qubit).index for qubit in qubits}