Skip to main content
IBM Quantum Platform
This page is from the dev version of Qiskit SDK. Go to the stable version.

Passmanager

qiskit.passmanager


Overview

The Qiskit pass manager is inspired by the LLVM compiler. The compiler infrastructure separates responsibilities into three main components: tasks, flow controllers, and pass managers.

A compilation pipeline executes a sequence of Task objects, each of which takes an intermediate representation (IR) as input, performs work, and returns a, possibly different, IR as output. Where Task defines the interface, an atomic task is a pass, which subclasses GenericPass and implements its abstract run() method. This is the class that should be used as base class when implementing a custom compiler pass.

Flow controllers provide execution models for a set of tasks. The simplest flow controller is a FlowControllerLinear, which simply executes a set of tasks in a linear sequence. More advanced flow controllers include loops or conditional execution. These are, for example, used in Qiskit’s preset transpiler pipelines for higher optimization levels where optimizations are run until a convergence criterion is met.

Pass managers are responsible for managing the tasks, including scheduling required analyses and enabling modification of the task sequence by the user. Qiskit provides two IR-generic pass managers in this module, and a pass manager specialized to DAGCircuit as IR in qiskit.transpiler. The IR-generic ones are:

  • BasePassManager: a pass manager with fixed IR. This pass manager allows modifying the set of tasks to be run and supports parallel execution of multiple inputs by means of parallel_map(). This class has support for additional conversion of an input program representation to the internal IR, and a conversion to an output program format.

    The BasePassManager is the base class for Qiskit’s preset pass managers for DAGCircuit transpilation, such as returned by generate_preset_pass_manager(). There, implicit conversions to and from QuantumCircuit as input and output program format are used.

  • MultiStagePassManager: a staged pass manager where each stage can preserve or lower the IR. A stage is defined by a Task or an iterable thereof, which can also be grouped inside a BasePassManager. The stages must be set up such that the output IR of the current stage matches the input IR of the next stage, there are (currently) no automatic translations.

Pass managers also provide infrastructure to pass a PropertySet with context-information through every task and a callback function for introspection. The PropertySet is a free-form dictionary, which can be populated and read by a pass during execution, or read by a flow-controller to control pass execution. The property set is portable and handed over from pass to pass at execution. In addition to the property set, tasks also receive a WorkflowStatus data structure. This object is initialized when the pass manager is run and handed over to underlying tasks. The status is updated after every pass is run, and contains information about the pipeline state (number of passes run, failure state, and so on) as opposed to the PropertySet, which contains information about the IR being optimized.

The callback is called by GenericPass instances expecting the following signature:

def callback(
    *,
    task: Task[IR_IN, IR_OUT],
    passmanager_ir: IR_OUT,
    property_set: PropertySet,
    running_time: float,
    count: int
) -> None:
    ...

Note that this signature differs slightly for passes and pass managers defined in the qiskit.transpiler module.


Examples

We look into a toy optimization task, namely, preparing a row of numbers and removing a digit if the number is five. Such a task might be easily done by converting the input numbers into string. We use the pass manager framework here, putting the efficiency aside for a moment to learn how to build a custom Qiskit compiler.

from qiskit.passmanager import BasePassManager, GenericPass, ConditionalController

class ToyPassManager(BasePassManager):

    def _passmanager_frontend(self, input_program: int, **kwargs) -> str:
        return str(input_program)

    def _passmanager_backend(self, passmanager_ir: str, in_program: int, **kwargs) -> int:
        return int(passmanager_ir)

This pass manager inputs and outputs an integer number, while performing the optimization tasks on a string data. Hence, input, IR, output type are integer, string, integer, respectively. The _passmanager_frontend() method defines the conversion from the input data to IR, and _passmanager_backend() defines the conversion from the IR to output data. The pass manager backend is also given an in_program parameter that contains the original input_program to the front end, for referencing any original metadata of the input program for the final conversion.

Next, we implement a pass that removes a digit when the number is five.

class RemoveFive(GenericPass):

    def run(self, passmanager_ir: str):
        return passmanager_ir.replace("5", "")

task = RemoveFive()

Finally, we instantiate a pass manager and schedule the task with it. Running the pass manager with a random row of numbers returns new numbers that don’t contain five.

pm = ToyPassManager()
pm.append(task)

pm.run([123456789, 45654, 36785554])

Output:

[12346789, 464, 36784]

Now we consider the case of conditional execution. We avoid execution of the “remove five” task when the input number is six digits or less. Such control can be implemented by a flow controller. We start from an analysis pass that provides the flow controller with information about the number of digits.

class CountDigits(GenericPass):

    def run(self, passmanager_ir: str):
        self.property_set["ndigits"] = len(passmanager_ir)

analysis_task = CountDigits()

Then, we wrap the remove five task with the ConditionalController that runs the stored tasks only when the condition is met.

def digit_condition(property_set):
    # Return True when condition is met.
    return property_set["ndigits"] > 6

conditional_task = ConditionalController(
    tasks=[RemoveFive()],
    condition=digit_condition,
)

As before, we schedule these passes with the pass manager and run.

pm = ToyPassManager()
pm.append(analysis_task)
pm.append(conditional_task)

pm.run([123456789, 45654, 36785554])

Output:

[12346789, 45654, 36784]

The “remove five” task is triggered only for the first and third input values, which have more than six digits.

With the pass manager framework, a developer can flexibly customize the optimization task by combining multiple passes and flow controllers. See details in the following class API documentation.


Interface

Passes

GenericPass()Base class of a single pass manager task.
Task()An interface of the pass manager task.

Pass managers

BasePassManager([tasks, max_iteration])Pass manager base class.
MultiStagePassManager(**stages)A staged pass manager supporting multiple IRs.

Flow controllers

BaseController([options])Base class of controller.
FlowControllerLinear([tasks, options])A standard flow controller that runs tasks one after the other.
ConditionalController([tasks, condition, ...])A flow controller runs the pipeline once if the condition is true, or does nothing if the condition is false.
DoWhileController([tasks, do_while, options])Run the given tasks in a loop until the do_while condition on the property set becomes False.

Compilation state

PropertySetA default dictionary-like object.
WorkflowStatus([count, completed_passes, ...])Collection of compilation status of workflow, i.e. pass manager run.
PassManagerState(workflow_status, property_set)A portable container object that pass manager tasks communicate through generator.

Exceptions

PassManagerError

exception qiskit.passmanager.PassManagerError(*message)

GitHub

Bases: QiskitError

Pass manager error.

Set the error message.

Was this page helpful?
Report a bug, typo, or request content on GitHub.