From 3de24f4fa2e9f2c6a9a6063bae97a4e4e9f70f4b Mon Sep 17 00:00:00 2001 From: Luciano Date: Sat, 15 Dec 2018 21:26:44 -0500 Subject: [PATCH] add_passes -> append (#1508) --- examples/python/using_qiskit_terra_level_2.py | 2 +- qiskit/transpiler/README.md | 26 ++--- qiskit/transpiler/_passmanager.py | 8 +- test/python/test_transpiler.py | 10 +- test/python/transpiler/test_pass_scheduler.py | 94 +++++++++---------- 5 files changed, 70 insertions(+), 70 deletions(-) diff --git a/examples/python/using_qiskit_terra_level_2.py b/examples/python/using_qiskit_terra_level_2.py index 80649f2102..7b7ec7e70c 100644 --- a/examples/python/using_qiskit_terra_level_2.py +++ b/examples/python/using_qiskit_terra_level_2.py @@ -51,7 +51,7 @@ print(compiled_standard.qasm()) # 2. custom compile -- customize PassManager to run specific circuit transformations from qiskit.transpiler.passes import CXCancellation pm = transpiler.PassManager() -pm.add_passes(CXCancellation()) +pm.append(CXCancellation()) dags = transpiler.transpile(circ, backend_device, pass_manager=pm) [compiled_custom] = dags print(compiled_custom.qasm()) diff --git a/qiskit/transpiler/README.md b/qiskit/transpiler/README.md index 66b3154c0b..84f8930d37 100644 --- a/qiskit/transpiler/README.md +++ b/qiskit/transpiler/README.md @@ -11,7 +11,7 @@ The main goal of Qiskit Terra's transpiler is to provide an extensible infrastru ### Pass Manager - A `PassManager` instance determines the schedule for running registered passes. - The pass manager is in charge of deciding the next pass to run, not the pass itself. -- Registering passes in the pass manager pipeline is done by the `add_passes` method. +- Registering passes in the pass manager pipeline is done by the `append` method. - While registering, you can specify basic control primitives over each pass (conditionals and loops). - Options to control the scheduler: - Passes can have arguments at init time that can affect their scheduling. If you want to set properties related to how the pass is run, you can do so by accessing these properties (e.g. pass_.max_iteration = 10). @@ -50,7 +50,7 @@ self.passmanager.add_flow_controller('do_x_times', DoXTimesController) This allows to use the parameter `do_x_times`, which needs to be a callable. In this case, this is used to parametrized the plugin, so it will for-loop 3 times. ``` -self.passmanager.add_passes([Pass()], do_x_times=lambda x : 3) +self.passmanager.append([Pass()], do_x_times=lambda x : 3) ``` @@ -60,10 +60,10 @@ The `CxCancellation` requires and preserves `ToffoliDecompose`. Same for `Rotati ``` pm = PassManager() -pm.add_passes(CxCancellation()) # requires: ToffoliDecompose / preserves: ToffoliDecompose -pm.add_passes(RotationMerge()) # requires: ToffoliDecompose / preserves: ToffoliDecompose -pm.add_passes(Mapper(coupling_map=coupling_map)) # requires: [] / preserves: [] -pm.add_passes(CxCancellation()) +pm.append(CxCancellation()) # requires: ToffoliDecompose / preserves: ToffoliDecompose +pm.append(RotationMerge()) # requires: ToffoliDecompose / preserves: ToffoliDecompose +pm.append(Mapper(coupling_map=coupling_map)) # requires: [] / preserves: [] +pm.append(CxCancellation()) ``` Given the above, the pass manager executes the following sequence of passes: @@ -79,9 +79,9 @@ Given the above, the pass manager executes the following sequence of passes: A pass behavior can be heavily influenced by its parameters. For example, unrolling using some basis gates is totally different than unrolling to different gates. And a PassManager might use both. ``` -pm.add_passes(Unroller(basis_gates=['id','u1','u2','u3','cx'])) -pm.add_passes(...) -pm.add_passes(Unroller(basis_gates=['U','CX'])) +pm.append(Unroller(basis_gates=['id','u1','u2','u3','cx'])) +pm.append(...) +pm.append(Unroller(basis_gates=['U','CX'])) ``` where (from `qelib1.inc`): @@ -101,7 +101,7 @@ There are cases when one or more passes have to be run repeatedly, until a condi ``` pm = PassManager() -pm.add_passes([CxCancellation(), RotationMerge(), CalculateDepth()], +pm.append([CxCancellation(), RotationMerge(), CalculateDepth()], do_while=lambda property_set: not property_set['fixed_point']['depth']) ``` The control argument `do_while` will run these passes until the callable returns `False`. The callable always takes in one argument, the pass manager's property set. In this example, `CalculateDepth` is an analysis pass that updates the property `depth` in the property set. @@ -110,9 +110,9 @@ The control argument `do_while` will run these passes until the callable returns The pass manager developer can avoid one or more passes by making them conditional (on a property in the property set): ``` -pm.add_passes(LayoutMapper(coupling_map)) -pm.add_passes(CheckIfMapped(coupling_map)) -pm.add_passes(BasicMapper(coupling_map), +pm.append(LayoutMapper(coupling_map)) +pm.append(CheckIfMapped(coupling_map)) +pm.append(BasicMapper(coupling_map), condition=lambda property_set: not property_set['is_mapped']) ``` diff --git a/qiskit/transpiler/_passmanager.py b/qiskit/transpiler/_passmanager.py index 512320e786..6841579b13 100644 --- a/qiskit/transpiler/_passmanager.py +++ b/qiskit/transpiler/_passmanager.py @@ -31,7 +31,7 @@ class PassManager(): max_iteration is reached. """ # the pass manager's schedule of passes, including any control-flow. - # Populated via PassManager.add_passes(). + # Populated via PassManager.append(). self.working_list = [] # global property set is the context of the circuit held by the pass manager @@ -50,7 +50,7 @@ class PassManager(): def _join_options(self, passset_options): """ Set the options of each passset, based on precedence rules: - passset options (set via ``PassManager.add_passes()``) override + passset options (set via ``PassManager.append()``) override passmanager options (set via ``PassManager.__init__()``), which override Default. . """ @@ -62,8 +62,8 @@ class PassManager(): passset_level = {k: v for k, v in passset_options.items() if v is not None} return {**default, **passmanager_level, **passset_level} - def add_passes(self, passes, ignore_requires=None, ignore_preserves=None, max_iteration=None, - **flow_controller_conditions): + def append(self, passes, ignore_requires=None, ignore_preserves=None, max_iteration=None, + **flow_controller_conditions): """ Args: passes (list[BasePass] or BasePass): pass(es) to be added to schedule diff --git a/test/python/test_transpiler.py b/test/python/test_transpiler.py index 323fdb32cb..19efb78b10 100644 --- a/test/python/test_transpiler.py +++ b/test/python/test_transpiler.py @@ -93,7 +93,7 @@ class TestTranspiler(QiskitTestCase): dag_circuit = circuit_to_dag(circuit) pass_manager = PassManager() - pass_manager.add_passes(CXCancellation()) + pass_manager.append(CXCancellation()) dag_circuit = transpile_dag(dag_circuit, pass_manager=pass_manager) resources_after = dag_circuit.count_ops() @@ -116,13 +116,13 @@ class TestTranspiler(QiskitTestCase): coupling_map = Coupling(couplinglist=[(0, 1), (0, 2)]) pass_manager = PassManager() - pass_manager.add_passes(LookaheadMapper(coupling_map)) + pass_manager.append(LookaheadMapper(coupling_map)) mapped_dag = transpile_dag(original_dag, pass_manager=pass_manager) self.assertEqual(original_dag, mapped_dag) second_pass_manager = PassManager() - second_pass_manager.add_passes(LookaheadMapper(coupling_map)) + second_pass_manager.append(LookaheadMapper(coupling_map)) remapped_dag = transpile_dag(mapped_dag, pass_manager=second_pass_manager) self.assertEqual(mapped_dag, remapped_dag) @@ -142,7 +142,7 @@ class TestTranspiler(QiskitTestCase): coupling_map = Coupling(couplinglist=[(0, 1), (1, 2)]) pass_manager = PassManager() - pass_manager.add_passes([LookaheadMapper(coupling_map)]) + pass_manager.append([LookaheadMapper(coupling_map)]) mapped_dag = transpile_dag(dag_circuit, pass_manager=pass_manager) self.assertEqual(mapped_dag.count_ops().get('swap', 0), @@ -170,7 +170,7 @@ class TestTranspiler(QiskitTestCase): coupling_map = Coupling(couplinglist=[(0, 1), (1, 2)]) pass_manager = PassManager() - pass_manager.add_passes([LookaheadMapper(coupling_map)]) + pass_manager.append([LookaheadMapper(coupling_map)]) mapped_dag = transpile_dag(dag_circuit, pass_manager=pass_manager) self.assertEqual(mapped_dag.count_ops().get('swap', 0), diff --git a/test/python/transpiler/test_pass_scheduler.py b/test/python/transpiler/test_pass_scheduler.py index 6cdccd1926..dfefc22794 100644 --- a/test/python/transpiler/test_pass_scheduler.py +++ b/test/python/transpiler/test_pass_scheduler.py @@ -66,10 +66,10 @@ class TestUseCases(SchedulerTestCase): def test_chain(self): """ A single chain of passes, with Requests and Preserves.""" - self.passmanager.add_passes(PassC_TP_RA_PA()) # Request: PassA / Preserves: PassA - self.passmanager.add_passes(PassB_TP_RA_PA()) # Request: PassA / Preserves: PassA - self.passmanager.add_passes(PassD_TP_NR_NP(argument1=[1, 2])) # Requires: {}/ Preserves: {} - self.passmanager.add_passes(PassB_TP_RA_PA()) + self.passmanager.append(PassC_TP_RA_PA()) # Request: PassA / Preserves: PassA + self.passmanager.append(PassB_TP_RA_PA()) # Request: PassA / Preserves: PassA + self.passmanager.append(PassD_TP_NR_NP(argument1=[1, 2])) # Requires: {}/ Preserves: {} + self.passmanager.append(PassB_TP_RA_PA()) self.assertScheduler(self.dag, self.passmanager, ['run transformation pass PassA_TP_NR_NP', 'run transformation pass PassC_TP_RA_PA', 'run transformation pass PassB_TP_RA_PA', @@ -80,25 +80,25 @@ class TestUseCases(SchedulerTestCase): def test_conditional_passes_true(self): """ A pass set with a conditional parameter. The callable is True. """ - self.passmanager.add_passes(PassE_AP_NR_NP(True)) - self.passmanager.add_passes(PassA_TP_NR_NP(), - condition=lambda property_set: property_set['property']) + self.passmanager.append(PassE_AP_NR_NP(True)) + self.passmanager.append(PassA_TP_NR_NP(), + condition=lambda property_set: property_set['property']) self.assertScheduler(self.dag, self.passmanager, ['run analysis pass PassE_AP_NR_NP', 'set property as True', 'run transformation pass PassA_TP_NR_NP']) def test_conditional_passes_false(self): """ A pass set with a conditional parameter. The callable is False. """ - self.passmanager.add_passes(PassE_AP_NR_NP(False)) - self.passmanager.add_passes(PassA_TP_NR_NP(), - condition=lambda property_set: property_set['property']) + self.passmanager.append(PassE_AP_NR_NP(False)) + self.passmanager.append(PassA_TP_NR_NP(), + condition=lambda property_set: property_set['property']) self.assertScheduler(self.dag, self.passmanager, ['run analysis pass PassE_AP_NR_NP', 'set property as False']) def test_conditional_and_loop(self): """ Run a conditional first, then a loop""" - self.passmanager.add_passes(PassE_AP_NR_NP(True)) - self.passmanager.add_passes( + self.passmanager.append(PassE_AP_NR_NP(True)) + self.passmanager.append( [PassK_check_fixed_point_property(), PassA_TP_NR_NP(), PassF_reduce_dag_property()], @@ -155,8 +155,8 @@ class TestUseCases(SchedulerTestCase): FlowController.remove_flow_controller('condition') FlowController.add_flow_controller('condition', ConditionalController) - self.passmanager.add_passes(PassK_check_fixed_point_property()) - self.passmanager.add_passes( + self.passmanager.append(PassK_check_fixed_point_property()) + self.passmanager.append( [PassK_check_fixed_point_property(), PassA_TP_NR_NP(), PassF_reduce_dag_property()], @@ -209,22 +209,22 @@ class TestUseCases(SchedulerTestCase): def test_do_not_repeat_based_on_preservation(self): """ When a pass is still a valid pass (because following passes preserved it), it should not run again""" - self.passmanager.add_passes([PassB_TP_RA_PA(), PassA_TP_NR_NP(), PassB_TP_RA_PA()]) + self.passmanager.append([PassB_TP_RA_PA(), PassA_TP_NR_NP(), PassB_TP_RA_PA()]) self.assertScheduler(self.dag, self.passmanager, ['run transformation pass PassA_TP_NR_NP', 'run transformation pass PassB_TP_RA_PA']) def test_do_not_repeat_based_on_idempotence(self): """ Repetition can be optimized to a single execution when the pass is idempotent""" - self.passmanager.add_passes(PassA_TP_NR_NP()) - self.passmanager.add_passes([PassA_TP_NR_NP(), PassA_TP_NR_NP()]) - self.passmanager.add_passes(PassA_TP_NR_NP()) + self.passmanager.append(PassA_TP_NR_NP()) + self.passmanager.append([PassA_TP_NR_NP(), PassA_TP_NR_NP()]) + self.passmanager.append(PassA_TP_NR_NP()) self.assertScheduler(self.dag, self.passmanager, ['run transformation pass PassA_TP_NR_NP']) def test_non_idempotent_pass(self): """ Two or more runs of a non-idempotent pass cannot be optimized. """ - self.passmanager.add_passes(PassF_reduce_dag_property()) - self.passmanager.add_passes([PassF_reduce_dag_property(), PassF_reduce_dag_property()]) - self.passmanager.add_passes(PassF_reduce_dag_property()) + self.passmanager.append(PassF_reduce_dag_property()) + self.passmanager.append([PassF_reduce_dag_property(), PassF_reduce_dag_property()]) + self.passmanager.append(PassF_reduce_dag_property()) self.assertScheduler(self.dag, self.passmanager, ['run transformation pass PassF_reduce_dag_property', 'dag property = 6', @@ -237,7 +237,7 @@ class TestUseCases(SchedulerTestCase): def test_fenced_property_set(self): """ Transformation passes are not allowed to modified the property set. """ - self.passmanager.add_passes(PassH_Bad_TP()) + self.passmanager.append(PassH_Bad_TP()) self.assertSchedulerRaises(self.dag, self.passmanager, ['run transformation pass PassH_Bad_TP'], TranspilerAccessError) @@ -253,7 +253,7 @@ class TestUseCases(SchedulerTestCase): circ.cx(qr[1], qr[0]) dag = circuit_to_dag(circ) - self.passmanager.add_passes(PassI_Bad_AP()) + self.passmanager.append(PassI_Bad_AP()) self.assertSchedulerRaises(dag, self.passmanager, ['run analysis pass PassI_Bad_AP', 'cx_runs: {(5, 6, 7, 8)}'], @@ -263,10 +263,10 @@ class TestUseCases(SchedulerTestCase): """ A pass manager that ignores requests does not run the passes decleared in the 'requests' field of the passes.""" passmanager = PassManager(ignore_requires=True) - passmanager.add_passes(PassC_TP_RA_PA()) # Request: PassA / Preserves: PassA - passmanager.add_passes(PassB_TP_RA_PA()) # Request: PassA / Preserves: PassA - passmanager.add_passes(PassD_TP_NR_NP(argument1=[1, 2])) # Requires: {} / Preserves: {} - passmanager.add_passes(PassB_TP_RA_PA()) + passmanager.append(PassC_TP_RA_PA()) # Request: PassA / Preserves: PassA + passmanager.append(PassB_TP_RA_PA()) # Request: PassA / Preserves: PassA + passmanager.append(PassD_TP_NR_NP(argument1=[1, 2])) # Requires: {} / Preserves: {} + passmanager.append(PassB_TP_RA_PA()) self.assertScheduler(self.dag, passmanager, ['run transformation pass PassC_TP_RA_PA', 'run transformation pass PassB_TP_RA_PA', 'run transformation pass PassD_TP_NR_NP', @@ -277,10 +277,10 @@ class TestUseCases(SchedulerTestCase): """ A pass manager that ignores preserves does not record the passes decleared in the 'preserves' field of the passes as valid passes.""" passmanager = PassManager(ignore_preserves=True) - passmanager.add_passes(PassC_TP_RA_PA()) # Request: PassA / Preserves: PassA - passmanager.add_passes(PassB_TP_RA_PA()) # Request: PassA / Preserves: PassA - passmanager.add_passes(PassD_TP_NR_NP(argument1=[1, 2])) # Requires: {} / Preserves: {} - passmanager.add_passes(PassB_TP_RA_PA()) + passmanager.append(PassC_TP_RA_PA()) # Request: PassA / Preserves: PassA + passmanager.append(PassB_TP_RA_PA()) # Request: PassA / Preserves: PassA + passmanager.append(PassD_TP_NR_NP(argument1=[1, 2])) # Requires: {} / Preserves: {} + passmanager.append(PassB_TP_RA_PA()) self.assertScheduler(self.dag, passmanager, ['run transformation pass PassA_TP_NR_NP', 'run transformation pass PassC_TP_RA_PA', 'run transformation pass PassA_TP_NR_NP', @@ -294,9 +294,9 @@ class TestUseCases(SchedulerTestCase): """ A pass manager that considers every pass as not idempotent, allows the immediate repetition of a pass""" passmanager = PassManager(ignore_preserves=True) - passmanager.add_passes(PassA_TP_NR_NP()) - passmanager.add_passes(PassA_TP_NR_NP()) # Normally removed for optimization, not here. - passmanager.add_passes(PassB_TP_RA_PA()) # Normally required is ignored for optimization, + passmanager.append(PassA_TP_NR_NP()) + passmanager.append(PassA_TP_NR_NP()) # Normally removed for optimization, not here. + passmanager.append(PassB_TP_RA_PA()) # Normally required is ignored for optimization, # not here self.assertScheduler(self.dag, passmanager, ['run transformation pass PassA_TP_NR_NP', 'run transformation pass PassA_TP_NR_NP', @@ -306,7 +306,7 @@ class TestUseCases(SchedulerTestCase): def test_pass_non_idempotence_passset(self): """ A pass set that is not idempotent. """ passmanager = PassManager() - passmanager.add_passes([PassA_TP_NR_NP(), PassB_TP_RA_PA()], ignore_preserves=True) + passmanager.append([PassA_TP_NR_NP(), PassB_TP_RA_PA()], ignore_preserves=True) self.assertScheduler(self.dag, passmanager, ['run transformation pass PassA_TP_NR_NP', 'run transformation pass PassA_TP_NR_NP', 'run transformation pass PassB_TP_RA_PA']) @@ -314,8 +314,8 @@ class TestUseCases(SchedulerTestCase): def test_analysis_pass_is_idempotent(self): """ Analysis passes are idempotent. """ passmanager = PassManager() - passmanager.add_passes(PassE_AP_NR_NP(argument1=1)) - passmanager.add_passes(PassE_AP_NR_NP(argument1=1)) + passmanager.append(PassE_AP_NR_NP(argument1=1)) + passmanager.append(PassE_AP_NR_NP(argument1=1)) self.assertScheduler(self.dag, passmanager, ['run analysis pass PassE_AP_NR_NP', 'set property as 1']) @@ -323,9 +323,9 @@ class TestUseCases(SchedulerTestCase): """ A default transformation does not preserves anything and analysis passes need to be re-run""" passmanager = PassManager() - passmanager.add_passes(PassE_AP_NR_NP(argument1=1)) - passmanager.add_passes(PassA_TP_NR_NP()) - passmanager.add_passes(PassE_AP_NR_NP(argument1=1)) + passmanager.append(PassE_AP_NR_NP(argument1=1)) + passmanager.append(PassA_TP_NR_NP()) + passmanager.append(PassE_AP_NR_NP(argument1=1)) self.assertScheduler(self.dag, passmanager, ['run analysis pass PassE_AP_NR_NP', 'set property as 1', 'run transformation pass PassA_TP_NR_NP', @@ -340,20 +340,20 @@ class TestUseCases(SchedulerTestCase): """ passmanager = PassManager(ignore_preserves=False, ignore_requires=True) tp_pass = PassA_TP_NR_NP() - passmanager.add_passes(tp_pass, ignore_preserves=True) + passmanager.append(tp_pass, ignore_preserves=True) the_pass_in_the_workinglist = next(iter(passmanager.working_list)) self.assertTrue(the_pass_in_the_workinglist.options['ignore_preserves']) self.assertTrue(the_pass_in_the_workinglist.options['ignore_requires']) def test_pass_no_return_a_dag(self): """ Passes instances with same arguments (independently of the order) are the same. """ - self.passmanager.add_passes(PassJ_Bad_NoReturn()) + self.passmanager.append(PassJ_Bad_NoReturn()) self.assertSchedulerRaises(self.dag, self.passmanager, ['run transformation pass PassJ_Bad_NoReturn'], TranspilerError) def test_fixed_point_pass(self): """ A pass set with a do_while parameter that checks for a fixed point. """ - self.passmanager.add_passes( + self.passmanager.append( [PassK_check_fixed_point_property(), PassA_TP_NR_NP(), PassF_reduce_dag_property()], @@ -404,7 +404,7 @@ class TestUseCases(SchedulerTestCase): def test_fixed_point_pass_max_iteration(self): """ A pass set with a do_while parameter that checks that the max_iteration is raised. """ - self.passmanager.add_passes( + self.passmanager.append( [PassK_check_fixed_point_property(), PassA_TP_NR_NP(), PassF_reduce_dag_property()], @@ -448,7 +448,7 @@ class TestControlFlowPlugin(SchedulerTestCase): def test_control_flow_plugin(self): """ Adds a control flow plugin with a single parameter and runs it. """ FlowController.add_flow_controller('do_x_times', DoXTimesController) - self.passmanager.add_passes([PassB_TP_RA_PA(), PassC_TP_RA_PA()], do_x_times=lambda x: 3) + self.passmanager.append([PassB_TP_RA_PA(), PassC_TP_RA_PA()], do_x_times=lambda x: 3) self.assertScheduler(self.dag, self.passmanager, ['run transformation pass PassA_TP_NR_NP', 'run transformation pass PassB_TP_RA_PA', 'run transformation pass PassC_TP_RA_PA', @@ -464,8 +464,8 @@ class TestControlFlowPlugin(SchedulerTestCase): self.assertEqual(controllers_length - 1, len(FlowController.registered_controllers)) FlowController.add_flow_controller('do_while', DoWhileController) self.assertEqual(controllers_length, len(FlowController.registered_controllers)) - self.passmanager.add_passes([PassB_TP_RA_PA(), PassC_TP_RA_PA()], - do_while=lambda property_set: True, max_iteration=2) + self.passmanager.append([PassB_TP_RA_PA(), PassC_TP_RA_PA()], + do_while=lambda property_set: True, max_iteration=2) self.assertSchedulerRaises(self.dag, self.passmanager, ['run transformation pass PassA_TP_NR_NP', 'run transformation pass PassB_TP_RA_PA',