-
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
Simplified experience with the transpiler using estimator. #10826
Comments
I'm a bit conflicted on the interface here, I agree with the goals of simplifying the interface around working with layout. But, I'm not a fan of splitting out the returns like that, just from a backwards compatibility standpoint it's a non-starter imo. It'd be too drastic a change to have multiple returns from The thing I was planning after #10818 is that the easy short term win here is to add some helper methods to def get_index_layout(transpiled_circuit: QuantumCircuit, num_source_qubits: int):
"""Get a list of final positions from a transpiled circuit and the input circuit's width
transpiled_circuit: The output circuit from the transpiler.
num_source_qubits: The number of qubits that were in the original circuit
"""
layout = transpiled_circuit.layout
if layout is None:
return list(range(num_source_qubits))
pos_to_virt = {v: k for k, v in layout.input_qubit_mapping.items()}
qubit_indices = []
for index in range(num_source_qubits):
qubit_idx = layout.initial_layout[pos_to_virt[index]]
if layout.final_layout is not None:
qubit_idx = layout.final_layout[transpiled_circuit.qubits[qubit_idx]]
qubit_indices.append(qubit_idx)
return qubit_indices which for the estimator gives you the positional mapping for each of the input circuit's qubits as a list you can use to permute the operator like what #9988 is trying to do. We could add similar easier to use alternatives for all the pieces about layout we want to expose so it's much easier to work with, but leave the current attributes in place to satisfy existing users of the API (which there are several out there because the current interface is all that is available for this). Then we can migrate to the newer better interface over time. The piece I'm not clear on is why the per pass layout transformation is important in the output. Having a log of how the transpiler updates the layout I don't think would be really helpful in most cases because we transform the layout at different points sometimes multiple times. The best example of the is |
As for the lower level details in the numbered list a lot of that already exists (the only thing which I don't remember off the top of my head is the approximation and error reporting), just in a different format or over different mechanisms. For example, we log a lot of the details already, so if you do something like:
you get the execution order and all the timing info as the passes run. For deeper inspection you can leverage the This lets you pretty much debug every step as it goes by and provides an interface for interacting with this data. For example: https://github.com/TheGupta2012/qiskit-timeline-debugger/tree/main is a tool that gives you a jupyter widget or a CLI tool to see the transforms each pass does as it executes and explore all the transforms and their effect on the circuit. The reason we do this via other mechanisms is that adding the details by default increases the complexity for the non-power user and also some of the introspection has noticeable runtime performance and memory overhead. So we're optimizing for the common path in the current interface design; which does add a couple of extra steps if you know what you're doing and want more detail. But, I think that's a reasonable tradeoff here, as the vast majority of our users aren't going to want to know the inner details of the transpiler. |
personally I don't use the other layouts but I can see how I might if I was optimizing for the swapping. The most important is a simple way to get the final layout |
as for working for 4 years it is because the default when including measurements is to transpile the measurements as well so backend.run works fine as an executor but as we move to estimator this becomes a huge problem. Unless we fix this estimator is essentially useless unless and here what we need is a pair circuits, observables that meet a common layout. |
This commit updates the TranspileLayout class to make it easier to work with. The TranspileLayout class was orginally just an a container class that took the information returned from the transpiler needed to reverse the transpiler layout permutation (in the absence of ancillas) so that `QuantumCircuit.from_circuit()` could compare Operator instances across a `transpile()`. However, the internal data structures used by the transpiler are hard to work with, and don't map well to the normal reasoning around how the transpiler transforms the circuit. To improve the usability of the class this commit adds 4 new methods to the class: - initial_layout_list() and final_layout_list() which compute a list form of the initial_layout and final_layout respectively - full_layout() which generates a list that maps the input circuits qubit positions in the input circuit to the final position at the end of the circuit (which is what most people think of when they hear "final layout") - permute_sparse_pauli_op() which takes in a SparsePauliOp object and permutes it based on the full layout. This is especially useful when combined with the Estimator primitive To implement these functions a few extra pieces of information are needed to fully implement them. The first is we need to know the number of original circuit qubits. This is used to account for any ancillas that are added in the circuit, once we have the input circuit count we can use the original_qubit_indices attribute to discern which qubits in the initial layout are from the original circuit and which are ancillas. The second piece of information needed is the list of qubits in the output circuit. as this is needed to look up the position of the virtual qubit in the final_layout. These are both added as optional private attributes to the TranspileLayout class and there are some small changes to the pass manager and QPY to accomodate them. Similarly the change in the TranspileLayout class requires a new QPY version to include the missing details that were not being serialized in QPY and weren't representable in the previous payload format. Fixes Qiskit#10826 Fixes Qiskit#10818
* Improve the ergonomics of the TranspileLayout class This commit updates the TranspileLayout class to make it easier to work with. The TranspileLayout class was orginally just an a container class that took the information returned from the transpiler needed to reverse the transpiler layout permutation (in the absence of ancillas) so that `QuantumCircuit.from_circuit()` could compare Operator instances across a `transpile()`. However, the internal data structures used by the transpiler are hard to work with, and don't map well to the normal reasoning around how the transpiler transforms the circuit. To improve the usability of the class this commit adds 4 new methods to the class: - initial_layout_list() and final_layout_list() which compute a list form of the initial_layout and final_layout respectively - full_layout() which generates a list that maps the input circuits qubit positions in the input circuit to the final position at the end of the circuit (which is what most people think of when they hear "final layout") - permute_sparse_pauli_op() which takes in a SparsePauliOp object and permutes it based on the full layout. This is especially useful when combined with the Estimator primitive To implement these functions a few extra pieces of information are needed to fully implement them. The first is we need to know the number of original circuit qubits. This is used to account for any ancillas that are added in the circuit, once we have the input circuit count we can use the original_qubit_indices attribute to discern which qubits in the initial layout are from the original circuit and which are ancillas. The second piece of information needed is the list of qubits in the output circuit. as this is needed to look up the position of the virtual qubit in the final_layout. These are both added as optional private attributes to the TranspileLayout class and there are some small changes to the pass manager and QPY to accomodate them. Similarly the change in the TranspileLayout class requires a new QPY version to include the missing details that were not being serialized in QPY and weren't representable in the previous payload format. Fixes #10826 Fixes #10818 * Handle None for the private TranspileLayout fields in QPY * Add test for full_layout with ancillas * Rework interface to be more consistent This commit reworks the names of the new methods added in this API to be more self consistent. It uses the format '*_index_layout' to replace the `*_layout_list` name. Similarly new methods `*_virtual_layout` are added for methods that return layout objects. * Apply suggestions from code review Co-authored-by: Jake Lishman <jake@binhbar.com> * Remove permute_sparse_pauli_op() This commit remove the TranspileLayout.permute_sparse_pauli_op() method. This was a bit out of place on the TranspileLayout class, and it will instead be replaced in a follow-up PR by a apply_layout() method on the SparePauliOp class that takes in a TranspileLayout object. * Update docs * Fix docs build post-rebase * Fix docs issues --------- Co-authored-by: Jake Lishman <jake@binhbar.com>
* Improve the ergonomics of the TranspileLayout class This commit updates the TranspileLayout class to make it easier to work with. The TranspileLayout class was orginally just an a container class that took the information returned from the transpiler needed to reverse the transpiler layout permutation (in the absence of ancillas) so that `QuantumCircuit.from_circuit()` could compare Operator instances across a `transpile()`. However, the internal data structures used by the transpiler are hard to work with, and don't map well to the normal reasoning around how the transpiler transforms the circuit. To improve the usability of the class this commit adds 4 new methods to the class: - initial_layout_list() and final_layout_list() which compute a list form of the initial_layout and final_layout respectively - full_layout() which generates a list that maps the input circuits qubit positions in the input circuit to the final position at the end of the circuit (which is what most people think of when they hear "final layout") - permute_sparse_pauli_op() which takes in a SparsePauliOp object and permutes it based on the full layout. This is especially useful when combined with the Estimator primitive To implement these functions a few extra pieces of information are needed to fully implement them. The first is we need to know the number of original circuit qubits. This is used to account for any ancillas that are added in the circuit, once we have the input circuit count we can use the original_qubit_indices attribute to discern which qubits in the initial layout are from the original circuit and which are ancillas. The second piece of information needed is the list of qubits in the output circuit. as this is needed to look up the position of the virtual qubit in the final_layout. These are both added as optional private attributes to the TranspileLayout class and there are some small changes to the pass manager and QPY to accomodate them. Similarly the change in the TranspileLayout class requires a new QPY version to include the missing details that were not being serialized in QPY and weren't representable in the previous payload format. Fixes Qiskit#10826 Fixes Qiskit#10818 * Handle None for the private TranspileLayout fields in QPY * Add test for full_layout with ancillas * Rework interface to be more consistent This commit reworks the names of the new methods added in this API to be more self consistent. It uses the format '*_index_layout' to replace the `*_layout_list` name. Similarly new methods `*_virtual_layout` are added for methods that return layout objects. * Apply suggestions from code review Co-authored-by: Jake Lishman <jake@binhbar.com> * Remove permute_sparse_pauli_op() This commit remove the TranspileLayout.permute_sparse_pauli_op() method. This was a bit out of place on the TranspileLayout class, and it will instead be replaced in a follow-up PR by a apply_layout() method on the SparePauliOp class that takes in a TranspileLayout object. * Update docs * Fix docs build post-rebase * Fix docs issues --------- Co-authored-by: Jake Lishman <jake@binhbar.com>
What should we add?
This is an issues beyond the bug I reported in #10818. As we start to work with the transpiler and use the estimator more the current flow is rather complicated. While most users can just send abstract quantum circuits to the system I want to be able to send logical circuits to the system using the gate set and coupling map I have. Given I know what I want to do I can in general make a better quantum circuit than the default optimizations and/or I can work on a better definition of the defaults.
In my view we should remove layout from being bound to the transpile circuit and have a layout object and meta data returned to the user after they run the transpiler. I think the workflow should be
personally I find the layout object over complex and should just be a list (I think @mtreinish shares my views here) and in the case that I need metadata from this transpliation I think we can put it all in a new object. I don't have strong opinions on it but some things that are interesting is to know how the layout was changed. Today we kinda get this as it is all put into a tranpilelayout object but it is not clear what pass did what (as I tried to explain in the bug #10818). My suggestion is that the meta data should contain
These are the ones I can think of for now
Finally we need a new function in the compiler and when I am using the estimator I want to be able to run using the layout from the transpiler.
that way I can send both
qc_transpile
andopts_transpile
to the estimator, while it is simple to write a few lines of code that is not the nicest user experience.This is very much related to Qiskit/qiskit-ibm-runtime#338 and solution #9988 but it is fundamental for the workflows using the estimator not only the ability to add ancillas if the transpiler enlarges the system but if the layout changes the layout object needs to be used to redefine the observables and even used in the post-processing if I want the data to be changed back to my original circuit order. We need to make layout a variable that people want to work with.
The text was updated successfully, but these errors were encountered: