-
Notifications
You must be signed in to change notification settings - Fork 2.4k
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
Integrate qiskit-toqm
as an optional package for layout and routing.
#7825
Conversation
Opening as a draft for now. It'd be great to get some early feedback on the approach, since it'd be nice to make TOQM available as part of the 0.20 release! |
Pull Request Test Coverage Report for Build 2496692372
💛 - Coveralls |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The approach looks good, a few comments:
-
can you add some more docstring under
ToqmStrategyO1
,ToqmStrategyO2
,ToqmStrategyO3
to describe what kind of parameters you are changing in each of them (in the qiskit-toqm repo)? -
please modify the docstring of the
transpile()
function to add'toqm'
to the list of possiblelayout_method
s androuting_method
s. -
can TOQM be viewed as a
scheduling_method
too? Recently in Split scheduling pass into scheduling and padding #7709 the scheduling methods (currently only ASAP and ALAP) have been made such that they populate anode_start_time
dictionary in the property set, which essentially puts absolute start time on the nodes. A follow up "padding" pass will actually insert the delays between those nodes. I wonder if TOQM can also populatenode_start_time
within it? Or are the timings too rough to do that?
does this need some tests? also should it be added as an optional dependency? |
This is currently necessary since Qiskit TOQM isn't published to PyPI for Linux aarch64 due to a bug.
I'm planning to make a few changes to the |
...when configured using one of its optimization strategies. This is because non-optimal configurations (i.e. anything using GreedyMapper under the hood) aren't compatible with the layout search parameter, and in fact break when it is provided. These configurations happen to always perform layout (without the explicit search) through a different means. To make everything consistent, it should be assumed that no matter which optimization strategy is used, layout changes will be made via routing. qiskit-toqm users can still create a custom strategy if they wish to use an optimal configuration that does not make layout changes, and then use their own pass manager.
@ajavadia and I have discussed some of this offline, but for others:
From an API perspective, the details of what's being changed behind these opt level-based strategies should be somewhat opaque, since we want the flexibility to change the behavior in future If users want to control specific parameters, they can create their own from qiskit_toqm import ToqmSwap, ToqmStrategy
import qiskit_toqm.native as toqm
class CustomStrategy(ToqmStrategy):
def run(self, gates, num_qubits):
mapper = toqm.ToqmMapper(
toqm.TrimSlowNodes(...),
toqm.GreedyTopK(...),
toqm.CXFrontier(),
toqm.Latency_1_2_6(),
[toqm.GreedyMapper()],
[],
0
)
mapper.setRetainPopped(1)
return mapper.run(gates, num_qubits, self.coupling_map) We can certainly improve the documentation of the native layer to make customization easier.
Done in 6f81c34.
TOQM cannot do this currently, since it works in terms of "cycles". These are different yet from
Testing added in c1bcec9. This testing aims only to cover the integration points with Terra, rather than the correctness of resulting circuits. This is because we don't want updates to
Is there something you have in mind other than what's been done already (i.e. adding |
About the very last point: you could potentially add an extra in |
from qiskit_toqm import ToqmSwap, ToqmStrategy
import qiskit_toqm.native as toqm
class CustomStrategy(ToqmStrategy):
def run(self, gates, num_qubits):
mapper = toqm.ToqmMapper(
toqm.TrimSlowNodes(...),
toqm.GreedyTopK(...),
toqm.CXFrontier(),
toqm.Latency_1_2_6(),
[toqm.GreedyMapper()],
[],
0
)
mapper.setRetainPopped(1)
return mapper.run(gates, num_qubits, self.coupling_map) I guess I'm fine if ToqmStrategy wraps all the options. But can't it be simplified a little? Like can't it just be something like from qiskit_toqm import ToqmStrategy
custom_strategy = ToqmStrategy(trim_slow_nodes=..., greedy_top_k=..., cx_frontier=...) and then ToqmStrategyO1 becomes a singleton instance of Is the class with the |
No I don't think we need to guarantee this. Just something that on average is true is fine (higher optimization level, more time, better output) |
It sounds like you're wondering if the The class with But now that I think about it a bit more, there's a level of indirection there we don't need, since we have all the information necessary to calculate instruction durations while constructing the pass manager. Further, cycle-based instruction durations should really only be computed if the strategy will actually use them. I'll try refactoring the |
As we have it now, the optimization strategies express more than just a native
|
This exercises the optimal mapper code paths of qiskit-toqm opt levels.
I ended up doing a bit of refactoring in qiskit-community/qiskit-toqm#23. That refactor moves all of the target-specific latency calculations out of As a side-effect, this allowed us to simplify the strategy hierarchy. The interface When constructing your own For example, to create a from qiskit_toqm import ToqmSwap, ToqmHeuristicStrategy, latencies_from_target
latencies = latencies_from_target(coupling_map, instruction_durations, basis_gates, backend_properties)
# or if you're using a V2 backend:
latencies = latencies_from_target(backend.target)
strategy = ToqmHeuristicStrategy(latencies, top_k=10, queue_target=1000, queue_max=2000)
swap = ToqmSwap(coupling_map, strategy) If you want to hard-code latencies rather than calculate them given a Terra target, you can use To create an optimal from qiskit_toqm import ToqmSwap, ToqmOptimalStrategy, latencies_from_simple
latencies = latencies_from_simple(one_qubit_cycles=1, two_qubit_cycles=2, swap_cycles=6)
strategy = ToqmOptimalStrategy(latencies, perform_layout=False)
swap = ToqmSwap(coupling_map, strategy) Note that |
Just want to point out as well that since this PR includes testing of the To avoid this, I think our options would be either:
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We should ensure that we've added an extras entry in the setup.py for the qiskit-toqm package. For example see: https://github.com/Qiskit/qiskit-terra/blob/main/setup.py#L48-L51 and https://github.com/Qiskit/qiskit-terra/blob/main/setup.py#L84-L93 for where we do this for other optional dependencies.
This honestly isn't any different then any other upstream dependency for testing (except that the responsibility is on us instead of others). If we release a qiskit-toqm package that breaks terra we'd have to pin the version until the breaking change is fixed. This happens semi-regularly with many of our dependencies that don't have good test coverage. If there is going to be a toqm usage in the terra repository it will need to be tested here, but we should also try to ensure that the qiskit-toqm package has sufficient test coverage to ensure that proposed changes to the qiskit-toqm won't break terra's usage. But if you're saying that the qiskit-toqm package doesn't provide sufficient api stability guarantees for us to rely on it that's a different story and maybe we shouldn't be integrating it into the terra repo yet until we've locked down what the api will look like. |
Ah, I see now what you and @jakelishman were getting at. I'll add this in an additional commit.
*EDITED*
This is fine with me. I think it's valuable to exercise the codepath that's hit when specifying
I'm happy with the current |
Should be ready for another look @ajavadia. |
d335c78
to
b2f6016
Compare
I like the new interface. Thanks for doing the refactoring. I'm good to merge after the conflict is resolved. Are the usage examples you have posted above for how to build strategies and latencies documented in qiskit_toqm? |
@ajavadia IIRC, I do need to update the docs in the |
Qiskit/qiskit#7825) * Integrate qiskit-toqm as an optional layout and routing pass. * Run formatting. * Add release note. * S * Exclude Linux aarch64 for qiskit-toqm in requirements-dev.txt. This is currently necessary since Qiskit TOQM isn't published to PyPI for Linux aarch64 due to a bug. * qiskit-toqm performs layout changes always. ...when configured using one of its optimization strategies. This is because non-optimal configurations (i.e. anything using GreedyMapper under the hood) aren't compatible with the layout search parameter, and in fact break when it is provided. These configurations happen to always perform layout (without the explicit search) through a different means. To make everything consistent, it should be assumed that no matter which optimization strategy is used, layout changes will be made via routing. qiskit-toqm users can still create a custom strategy if they wish to use an optimal configuration that does not make layout changes, and then use their own pass manager. * Add basic testing for TOQM integration. * Update to use qiskit-toqm 0.0.3 API. * Add testing of 5 qubit device. This exercises the optimal mapper code paths of qiskit-toqm opt levels. * Update for target awareness. * Add extra to setup.py for toqm. * Bump requirement-dev.txt TOQM version.
Summary
Integrates the
ToqmSwap
layout and routing pass from Qiskit TOQM via an optional package for all preset pass managers.Details and comments
Qiskit TOQM is implemented on top of libtoqm, a C++ library-ified version of the original reference implementation published with Time-Optimial Qubit Mapping.
The integration points aim to be minimal in support of the somewhat distant goal of the transpiler being pluggable. For now, the goal here is to make TOQM easily accessible to users and easy to update without locking it against Terra's release cadence.
Because there's not yet been enough experimentation to deduce the best TOQM configurations for each preset pass manager,
qiskit-toqm
exposes "strategies" for optimization levels (O1, O2, O3) maintained within. As we determine the appropriate settings for Terra, we can easily update the behavior by modifying those strategies. Users that desire more control can construct their own pass manager and specify a custom strategy callable which offers complete control over the underlying invocation oflibtoqm
with access to information about the current DAG and target.TODO:
qiskit-toqm
is not yet available in PyPI.