Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Legacy code removal in pass manager #11448

Merged
merged 15 commits into from
Jan 10, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 0 additions & 2 deletions qiskit/passmanager/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -209,7 +209,6 @@ def digit_condition(property_set):
.. autosummary::
:toctree: ../stubs/

FlowController
FlowControllerLinear
ConditionalController
DoWhileController
Expand All @@ -232,7 +231,6 @@ def digit_condition(property_set):

from .passmanager import BasePassManager
from .flow_controllers import (
FlowController,
FlowControllerLinear,
ConditionalController,
DoWhileController,
Expand Down
222 changes: 1 addition & 221 deletions qiskit/passmanager/flow_controllers.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,9 +15,8 @@

import logging
from collections.abc import Callable, Iterable, Generator
from typing import Type, Any
from typing import Any

from qiskit.utils.deprecation import deprecate_func
from .base_tasks import BaseController, Task
from .compilation_status import PassManagerState, PropertySet
from .exceptions import PassManagerError
Expand Down Expand Up @@ -45,31 +44,6 @@ def passes(self) -> list[Task]:
"""Alias of tasks for backward compatibility."""
return list(self.tasks)

@deprecate_func(
since="0.45.0",
additional_msg="All tasks must be provided at construction time of the controller object.",
)
def append(
self,
passes: Task | list[Task],
):
"""Add new task to pipeline.

Args:
passes: A new task or list of tasks to add.
"""
if not isinstance(passes, Iterable):
passes = [passes]

tasks = list(self.tasks)
for task in passes:
if not isinstance(task, Task):
raise TypeError(
f"New task {task} is not a valid pass manager pass or flow controller."
)
tasks.append(task)
self.tasks = tuple(tasks)

def iter_tasks(self, state: PassManagerState) -> Generator[Task, PassManagerState, None]:
for task in self.tasks:
state = yield task
Expand Down Expand Up @@ -101,31 +75,6 @@ def passes(self) -> list[Task]:
"""Alias of tasks for backward compatibility."""
return list(self.tasks)

@deprecate_func(
since="0.45.0",
additional_msg="All tasks must be provided at construction time of the controller object.",
)
def append(
self,
passes: Task | list[Task],
):
"""Add new task to pipeline.

Args:
passes: A new task or list of tasks to add.
"""
if not isinstance(passes, Iterable):
passes = [passes]

tasks = list(self.tasks)
for task in passes:
if not isinstance(task, Task):
raise TypeError(
f"New task {task} is not a valid pass manager pass or flow controller."
)
tasks.append(task)
self.tasks = tuple(tasks)

def iter_tasks(self, state: PassManagerState) -> Generator[Task, PassManagerState, None]:
max_iteration = self._options.get("max_iteration", 1000)
for _ in range(max_iteration):
Expand Down Expand Up @@ -161,176 +110,7 @@ def passes(self) -> list[Task]:
"""Alias of tasks for backward compatibility."""
return list(self.tasks)

@deprecate_func(
since="0.45.0",
additional_msg="All tasks must be provided at construction time of the controller object.",
)
def append(
self,
passes: Task | list[Task],
):
"""Add new task to pipeline.

Args:
passes: A new task or list of tasks to add.
"""
if not isinstance(passes, Iterable):
passes = [passes]

tasks = list(self.tasks)
for task in passes:
if not isinstance(task, Task):
raise TypeError(
f"New task {task} is not a valid pass manager pass or flow controller."
)
tasks.append(task)
self.tasks = tuple(tasks)

def iter_tasks(self, state: PassManagerState) -> Generator[Task, PassManagerState, None]:
if self.condition(state.property_set):
for task in self.tasks:
state = yield task


class FlowController(BaseController):
"""A legacy factory for other flow controllers.

.. warning::

This class is primarily for compatibility with legacy versions of Qiskit, and in general,
you should prefer simply instantiating the controller you want, and adding it to the
relevant :class:`.PassManager` or other controller. Its use is deprecated.

This allows syntactic sugar for writing pipelines. For example::

FlowController.add_flow_controller("my_condition", CustomController)

controller = FlowController.controller_factory(
[PassA(), PassB()],
{"max_iteration": 1000},
condition=lambda prop_set: prop_set["x"] == 0,
do_while=lambda prop_set: prop_set["x"] < 100,
my_condition=lambda prop_set: prop_set["y"] = "abc",
)

This creates a nested flow controller that runs when the value :code:`x` in the
:class:`.PropertySet` is zero and repeats the pipeline until the value becomes 100.
In each innermost loop, the custom iteration condition provided by
the ``CustomController`` is also evaluated.

.. warning::

:class:`.BaseController` must be directly subclassed to define a custom flow controller.
This class provides a controller factory method, which consumes a class variable
:attr:`.registered_controllers`. Subclassing FlowController may cause
unexpected behavior in the factory method.
Note that factory method implicitly determines the priority of the builtin controllers
when multiple controllers are called together,
and the behavior of generated controller is hardly debugged.
"""

registered_controllers = {
"condition": ConditionalController,
"do_while": DoWhileController,
}
hierarchy = [
"condition",
"do_while",
]

@classmethod
@deprecate_func(
since="0.45.0",
additional_msg=(
"Controller object must be explicitly instantiated. "
"Building controller with keyword arguments may yield race condition when "
"multiple keyword arguments are provided together, which is likely unsafe."
),
)
def controller_factory(
cls,
passes: Task | list[Task],
options: dict,
**controllers,
):
"""Create a new flow controller with normalization.

Args:
passes: A list of optimization tasks.
options: Option for this flow controller.
controllers: Dictionary of controller callables keyed on flow controller alias.

Returns:
An instance of normalized flow controller.
"""
if None in controllers.values():
raise PassManagerError("The controller needs a callable. Value cannot be None.")

if isinstance(passes, BaseController):
instance = passes
else:
instance = FlowControllerLinear(passes, options=options)

if controllers:
# Alias in higher hierarchy becomes outer controller.
for alias in cls.hierarchy[::-1]:
if alias not in controllers:
continue
class_type = cls.registered_controllers[alias]
init_kwargs = {
"options": options,
alias: controllers.pop(alias),
}
instance = class_type([instance], **init_kwargs)

return instance

@classmethod
@deprecate_func(
since="0.45.0",
additional_msg=(
"Controller factory method is deprecated and managing the custom flow controllers "
"with alias no longer helps building the task pipeline. "
"Controllers must be explicitly instantiated and appended to the pipeline."
),
)
def add_flow_controller(
cls,
name: str,
controller: Type[BaseController],
):
"""Adds a flow controller.

Args:
name: Alias of controller class in the namespace.
controller: Flow controller class.
"""
cls.registered_controllers[name] = controller
if name not in cls.hierarchy:
cls.hierarchy.append(name)

@classmethod
@deprecate_func(
since="0.45.0",
additional_msg=(
"Controller factory method is deprecated and managing the custom flow controllers "
"with alias no longer helps building the task pipeline. "
"Controllers must be explicitly instantiated and appended to the pipeline."
),
)
def remove_flow_controller(
cls,
name: str,
):
"""Removes a flow controller.

Args:
name: Alias of the controller to remove.

Raises:
KeyError: If the controller to remove was not registered.
"""
if name not in cls.hierarchy:
raise KeyError("Flow controller not found: %s" % name)
del cls.registered_controllers[name]
cls.hierarchy.remove(name)
13 changes: 1 addition & 12 deletions qiskit/transpiler/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -1231,15 +1231,6 @@

InstructionDurations

Fenced Objects
--------------

.. autosummary::
:toctree: ../stubs/

FencedPropertySet
FencedDAGCircuit

Abstract Passes
---------------

Expand All @@ -1262,22 +1253,20 @@

# For backward compatibility
from qiskit.passmanager import (
FlowController,
ConditionalController,
DoWhileController,
)
from qiskit.passmanager.compilation_status import PropertySet

from .passmanager import PassManager, StagedPassManager
from .passmanager_config import PassManagerConfig
from .propertyset import PropertySet # pylint: disable=no-name-in-module
from .exceptions import (
TranspilerError,
TranspilerAccessError,
CouplingError,
LayoutError,
CircuitTooWideForTarget,
)
from .fencedobjs import FencedDAGCircuit, FencedPropertySet
from .basepasses import AnalysisPass, TransformationPass
from .coupling import CouplingMap
from .layout import Layout, TranspileLayout
Expand Down
78 changes: 0 additions & 78 deletions qiskit/transpiler/fencedobjs.py

This file was deleted.

Loading