Código fonte de qiskit.transpiler.passes.utils.minimum_point
# This code is part of Qiskit.
#
# (C) Copyright IBM 2023
#
# This code is licensed under the Apache License, Version 2.0. You may
# obtain a copy of this license in the LICENSE.txt file in the root directory
# of this source tree or at http://www.apache.org/licenses/LICENSE-2.0.
#
# Any modifications or derivative works of this code must retain this
# copyright notice, and modified files need to carry a notice indicating
# that they have been altered from the originals.
"""Check if the DAG has reached a relative semi-stable point over previous runs."""
from copy import deepcopy
from dataclasses import dataclass
import math
from typing import Tuple
from qiskit.dagcircuit.dagcircuit import DAGCircuit
from qiskit.transpiler.basepasses import TransformationPass
[documentos]class MinimumPoint(TransformationPass):
"""Check if the DAG has reached a relative semi-stable point over previous runs
This pass is similar to the :class:`~.FixedPoint` transpiler pass and is intended
primarily to be used to set a loop break condition in the property set.
However, unlike the :class:`~.FixedPoint` class which only sets the
condition if 2 consecutive runs have the same value property set value
this pass is designed to find a local minimum and use that instead. This
pass is designed for an optimization loop where a fixed point may never
get reached (for example if synthesis is used and there are multiple
equivalent outputs for some cases).
This pass will track the state of fields in the property set over its past
executions and set a boolean field when either a fixed point is reached
over the backtracking depth or selecting the minimum value found if the
backtracking depth is reached. To do this it stores a deep copy of the
current minimum DAG in the property set and when ``backtrack_depth`` number
of executions is reached since the last minimum the output dag is set to
that copy of the earlier minimum.
Fields used by this pass in the property set are (all relative to the ``prefix``
argument):
* ``{prefix}_minimum_point_state`` - Used to track the state of the minimpoint search
* ``{prefix}_minimum_point`` - This value gets set to ``True`` when either a fixed point
is reached over the ``backtrack_depth`` executions, or ``backtrack_depth`` was exceeded
and an earlier minimum is restored.
"""
def __init__(self, property_set_list, prefix, backtrack_depth=5):
"""Initialize an instance of this pass
Args:
property_set_list (list): A list of property set keys that will
be used to evaluate the local minimum. The values of these
property set keys will be used as a tuple for comparison
prefix (str): The prefix to use for the property set key that is used
for tracking previous evaluations
backtrack_depth (int): The maximum number of entries to store. If
this number is reached and the next iteration doesn't have
a decrease in the number of values the minimum of the previous
n will be set as the output dag and ``minimum_point`` will be set to
``True`` in the property set
"""
super().__init__()
self.property_set_list = property_set_list
self.backtrack_name = f"{prefix}_minimum_point_state"
self.minimum_reached = f"{prefix}_minimum_point"
self.backtrack_depth = backtrack_depth
[documentos] def run(self, dag):
"""Run the MinimumPoint pass on `dag`."""
score = tuple(self.property_set[x] for x in self.property_set_list)
state = self.property_set[self.backtrack_name]
# The pass starts at None and the first iteration doesn't set a real
# score so the overall loop is treated as a do-while to ensure we have
# at least 2 iterations.
if state is None:
self.property_set[self.backtrack_name] = _MinimumPointState(
dag=None, score=(math.inf,) * len(self.property_set_list), since=0
)
# If the score of this execution is worse than the previous execution
# increment 'since' since we have not found a new minimum point
elif score > state.score:
state.since += 1
if state.since == self.backtrack_depth:
self.property_set[self.minimum_reached] = True
return self.property_set[self.backtrack_name].dag
# If the score has decreased (gotten better) then this iteration is
# better performing and this iteration should be the new minimum state.
# So update the state to be this iteration and reset counter
elif score < state.score:
state.since = 1
state.score = score
state.dag = deepcopy(dag)
# If the current execution is equal to the previous minimum value then
# we've reached an equivalent fixed point and we should use this iteration's
# dag as the output and set the property set flag that we've found a minimum
# point.
elif score == state.score:
self.property_set[self.minimum_reached] = True
return dag
return dag
@dataclass
class _MinimumPointState:
__slots__ = ("dag", "score", "since")
dag: DAGCircuit
score: Tuple[float, ...]
since: int