MultiStagePassManager
class qiskit.passmanager.MultiStagePassManager(**stages)
Bases : Generic[IR, IR_OUT]
Un gestionnaire de passes par étapes prenant en charge plusieurs IR.
Ce gestionnaire de passes exécute des étapes séquentielles et nommées sur le programme d'entrée. Une étape peut être définie comme Task, un itérable de celle-ci, ou comme un BasePassManager. Si un BasePassManager est défini comme étape, seules les tâches qu’il contient sont exécutées; les conversions d’entrée et de sortie définies par ses _passmanager_backend méthodes et _passmanager_frontend ne sont _pas_ appliquées.
Les étapes permettent de :
- conserver l'IR, par exemple s'il est défini sur
BasePassManager[IR]ouTask[IR, IR], ou - réduire l'IR, par exemple à
Task[IR1, IR2].
Il incombe à l'utilisateur de configurer les étages de manière compatible, de sorte que la réponse en impulsion (IR) de sortie de l'étage actuel corresponde à la réponse en impulsion (IR) d'entrée de l'étage suivant. Les noms des étapes et l'ordre dans lequel elles s'exécutent sont définis lors de la création du gestionnaire de passes. L'implémentation d'une étape peut être modifiée en attribuant une nouvelle implémentation à l'attribut correspondant de l'objet.
Si une fonction de rappel est fournie à la run() méthode, elle doit être capable de gérer le fait que son entrée IR puisse correspondre à n'importe quel type de sortie généré par les tâches du gestionnaire de passes.
La fonction de rappel est appelée avec la signature suivante :
def callback(
task: Task, # the executed task
passmanager_ir: Any, # the IR after the task execution
property_set: PropertySet, # the property set after execution
running_time: float, # the time the task ran
count: int # the number of executed tasks so far
):
...Tous les arguments sont transmis sous forme d'arguments par mot-clé.
Alors que l'objet Task définit l'interface de la tâche, les passes personnalisées ne doivent dériver que de la classe de base GenericPass. La base Task est une interface interne, et les prochaines versions de Qiskit pourraient imposer davantage de restrictions quant aux types disponibles Task.
Voici un exemple de flux de travail :
from qiskit.circuit import QuantumCircuit
from qiskit.dagcircuit import DAGCircuit
from qiskit.passmanager import GenericPass, MultiStagePassManager
from qiskit.transpiler import generate_preset_pass_manager, Target, CouplingMap
class CustomPauliIR:
# A custom IR of global Pauli strings
def __init__(self, num_qubits):
self.num_qubits = num_qubits
self.paulis = []
def apply(self, pauli: str):
assert len(pauli) == self.num_qubits
self.paulis.append(pauli)
class CustomPauliOptimization(GenericPass[CustomPauliIR, CustomPauliIR]):
# A pass run on the custom Pauli IR
def run(self, passmanager_ir: CustomPauliIR) -> CustomPauliIR:
to_remove = []
for i, pauli in enumerate(passmanager_ir.paulis):
if all(p == "I" for p in pauli):
to_remove.append(i)
for i in reversed(to_remove):
del passmanager_ir.paulis[i]
return passmanager_ir
class PauliToDAG(GenericPass[CustomPauliIR, DAGCircuit]):
# A pass converting CustomPauliIR to DAGCircuit
def run(self, passmanager_ir: CustomPauliIR) -> DAGCircuit:
circuit = QuantumCircuit(passmanager_ir.num_qubits)
for pauli in passmanager_ir.paulis:
circuit.pauli(pauli, circuit.qubits)
return circuit.to_dag()
def callback(task, passmanager_ir, property_set, running_time, count):
if isinstance(passmanager_ir, CustomPauliIR):
print("PauliIR:", task.__class__.__name__, passmanager_ir.paulis)
else:
print("DAGCircuit:", task.__class__.__name__, passmanager_ir.count_ops())
target = Target.from_configuration(
basis_gates=["u", "cx"], coupling_map=CouplingMap.from_line(3)
)
multi_pm = MultiStagePassManager(
pauli_opt=CustomPauliOptimization(),
pauli_to_dag=PauliToDAG(),
dag_opt=generate_preset_pass_manager(target=target),
)
program = CustomPauliIR(3)
program.apply("XYZ")
program.apply("III")
program.apply("ZZI")
out = multi_pm.run(program, callback=callback)
print(out.count_ops())Cette classe est apparentée à StagedPassManager dans la mesure où toutes deux présentent un modèle d'exécution par étapes. Le StagedPassManager, cependant, n'autorise DAGCircuit que comme IR, dispose de conversions implicites depuis et vers un QuantumCircuit aux niveaux d'entrée et de sortie, et comporte des hooks implicites pre_* de stade et post_* dans lesquels il est possible d'écrire.
La logique d'exécution d'un StagedPassManager est à peu près équivalente à :
from qiskit.circuit import QuantumCircuit
from qiskit.dagcircuit import DAGCircuit
from qiskit.passmanager import GenericPass, MultiStagePassManager
from qiskit.transpiler import TranspileLayout
class CircuitToDAG(GenericPass[QuantumCircuit, DAGCircuit]):
def run(self, passmanager_ir: QuantumCircuit) -> DAGCircuit:
self.property_set["original_qubit_indices"] = {
bit: i for i, bit in enumerate(passmanager_ir.qubits)
}
self.property_set["num_input_qubits"] = passmanager_ir.num_qubits
return passmanager_ir.to_dag()
class DAGToCircuit(GenericPass[DAGCircuit, QuantumCircuit]):
def run(self, passmanager_ir: DAGCircuit) -> QuantumCircuit:
qc = passmanager_ir.to_circuit(copy_operations=False)
qc._layout = TranspileLayout.from_property_set(passmanager_ir, self.property_set)
return qc
multi_pm = MultiStagePassManager(
input=CircuitToDAG(),
# ... stages of StagedPassManager ...
output=DAGToCircuit()
)
input_circuit = QuantumCircuit(1)
output_circuit = multi_pm.run(input_circuit)Le modèle d'exécution actuel linéarise le passage en un FlowControllerLinear afin d'exécuter les tâches. Ce modèle sous-jacent est susceptible d'évoluer et il n'est pas prudent de se baser sur cette hypothèse. Les interfaces publiques de cette classe sont toutefois stables.
Paramètres
stages (BasePassManager[Any] | Task[Any, Any] | Iterable[Task[Any, Any]]) –
Les étapes en tant que gestionnaires de passes. Celles-ci seront exécutées dans l'ordre indiqué et doivent avoir des IR compatibles.
Les noms des étapes sont définis par le constructeur; vous ne pouvez pas ajouter de nouvelles étapes par la suite, mais vous pouvez remplacer l'implémentation de chaque étape en réaffectant son attribut.
Attributs
stages
Les noms de scène. Ceux-ci sont immuables.
Les étapes elles-mêmes peuvent être modifiées en écrivant dans l'attribut portant le même nom que l'étape.
Méthodes
run
run(in_programs, callback=None, *, property_set=None)
Exécutez le gestionnaire de passes sur un ensemble de programmes d'entrée.
Paramètres
- in_programs (IR | list[IR] | tuple[IR]) – Les programmes sur lesquels le gestionnaire de mots de passe doit s'exécuter.
- callback (Callable[[Task, Any, PropertySet, float, int], None] | None) – Une fonction de rappel transmise à chaque tâche individuelle.
- property_set (PropertySet | None) – Une propriété facultative à transmettre au gestionnaire de passes. Si cette valeur est fournie, elle sera modifiée directement. Cette fonctionnalité ne peut pas être utilisée avec plusieurs programmes.
Retours
Les programmes de sortie.
Type de retour
IR_OUT | Iterable [ IR_OUT ]
to_flow_controller
to_flow_controller()
Convertissez ce gestionnaire de passages à plusieurs étapes en un régulateur de débit linéaire.
Cette conversion normalise ce gestionnaire de passes en un Task[IR, IR_OUT] et permet de l'imbriquer à l'intérieur d'un MultiStagePassManager lui-même ou d'autres flux d'exécution.
Type de retour
Flow[* ControllerLinearIR*, IR_OUT]