-
Notifications
You must be signed in to change notification settings - Fork 2.3k
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
Update backend model up-conversion logic #11095
Update backend model up-conversion logic #11095
Conversation
…_target from qiskit.providers.backend_compat.py with contents of method target_from_server_data from qiskit_ibm_provider/utils/json_decoder.py
Thank you for opening a new pull request. Before your PR can be merged it will first need to pass continuous integration tests and be reviewed. Sometimes the review process can be slow, so please be patient. While you're waiting, please feel free to review other open PRs. While only a subset of people are authorized to approve pull requests for merging, everyone is encouraged to review open pull requests. Doing reviews helps reduce the burden on the core team and helps make the project's code better for everyone. One or more of the the following people are requested to review this:
|
@to24toro , please have a look if this is good enough :) |
qiskit/providers/backend_compat.py
Outdated
return qubit_props | ||
|
||
|
||
def convert_to_target_legacy( |
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 would like to replace this convert_to_target_legacy
with new one.
Maybe you separate them because these have two different inputs.
I think that it might be better to deprecate unnecessary inputs in new convert_to_target
.
In Qiskit development process, we need to add deprecate_arg
before change API. (you can see some examples if you search @deprecate_arg
in qiskit.)
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.
I have not deprecated any argument of convert_to_target
because these arguments are used in BackendV2Converter
of backend_compat.py
.
Aer specifically uses argument custom_name_mapping
to pass in all aer related instructions to target
. The reason I separated old codes into convert_to_target_legacy
was because in this PR I just focused on introducing convert_to_target
to FakeBackendV2
.
Now, there is no convert_to_target_legacy
, only one function convert_to_target
is passed to both FakeBackendV2
and BackendV2Converter
.
All arguments of convert_to_target
are relevant and works fine to my knowledge :)
qiskit/providers/backend_compat.py
Outdated
from qiskit.transpiler.target import Target | ||
from qiskit.circuit.controlflow import ForLoopOp, IfElseOp, SwitchCaseOp, WhileLoopOp | ||
from qiskit.circuit.library.standard_gates import get_standard_gate_name_mapping | ||
from qiskit.qobj.pulse_qobj import PulseLibraryItem | ||
from qiskit.qobj.converters.pulse_instruction import QobjToInstructionConverter | ||
from qiskit.providers.models.pulsedefaults import Command | ||
from qiskit.pulse.calibration_entries import PulseQobjDef | ||
from qiskit.circuit.parameter import Parameter | ||
from qiskit.circuit.gate import Gate |
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.
All of them leads to cyclic-import?
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.
Only from qiskit.transpiler.target import Target
causes the cyclic-import problem.
But, since these imports are only used in convert_to_target
I have kept it into this function only.
This is because, had I put it outside(on the top) it would cause the same cyclic-import in the future if any other function finds a way into this file which could use imports that cause cyclic-import problems, so the best solution here is to do imports at the site of usage! :)
I would change these if you say so :)
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.
Thank you for your PR and sorry for late response.
I think that it is almost well done.
My suggestions consist of
- IBMQubitProperties
Careful discussion is needed before adding the new class. If possible, we would like to avoid adding it. - Input consistency between the new convert_to_target and the legacy one.
It would be better to keep inputs as they are. If we want to drop it, we can do that after warning users in the next release.
@nkanazawa1989 |
Pull Request Test Coverage Report for Build 7140509075Warning: This coverage report may be inaccurate.We've detected an issue with your CI configuration that might affect the accuracy of this pull request's coverage report.
💛 - Coveralls |
…emoved source code for convert_to_target_legacy function from backend_compat.py.
Thank you for opening a new pull request. Before your PR can be merged it will first need to pass continuous integration tests and be reviewed. Sometimes the review process can be slow, so please be patient. While you're waiting, please feel free to review other open PRs. While only a subset of people are authorized to approve pull requests for merging, everyone is encouraged to review open pull requests. Doing reviews helps reduce the burden on the core team and helps make the project's code better for everyone. One or more of the the following people are requested to review this:
|
@to24toro , please see if this is ok :) |
|
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.
Thanks @MozammilQ ! We wanted to unify the machinery for backend model up-conversion. So far we have been maintaining only one in the IBM Provider, and current Qiskit code is bit fragile. This PR will make the up-conversion logic more robust. Probably @mtreinish also wants to take a look?
This is nitpick but the scope of this PR seems wider than what the PR title describes. To avoid confusion in the commit log, I prefer other PR title such as "Update backend model up-conversion logic". You can write upgrade and fix in the release note, i.e. new logic provides better handling for control flow instructions.
@nkanazawa1989 , please see if this is good enough :) |
qiskit/providers/backend_compat.py
Outdated
def convert_to_target( | ||
configuration: BackendConfiguration, | ||
properties: BackendProperties = None, | ||
defaults: PulseDefaults = None, | ||
properties: Optional[Union[BackendProperties, Dict]] = None, | ||
defaults: Optional[Union[PulseDefaults, Dict]] = None, | ||
custom_name_mapping: Optional[Dict[str, Any]] = None, | ||
add_delay: bool = False, | ||
filter_faulty: bool = False, | ||
add_delay: bool = True, | ||
filter_faulty: bool = True, | ||
): |
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.
@MozammilQ
I apologize for the delayed response.
I would like to make one comment.
The default value for this part(e.g. add_delay) of the input has been changed. Ideally, in the upcoming 0.46 version, the deprecate_aeg
decorator should be added on this function, and the in 0.47 and beyond, these input should be changed from the default. However, this PR for the main branch signified the merge for the Qiskit 1.0, and we don’t allow API change for a year.
As a special case, we are considering allowing the direct modification of the default values for input without the decorator in this PR.
Therefore, after this PR merge, we would like you to submit a new PR to the 0.46 branch with the added decorator.
Thank you.
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.
Thanks @MozammilQ the PR looks almost good to me except for handling of calibration data. I'll approve once after the change is applied :)
@nkanazawa1989 , please see if this is good enough :) |
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.
Thanks @MozammilQ and @to24toro . Overall the PR looks good. I just added some suggestions to make code more readable and efficient. This doesn't block merge, so it's up to you. I'll approve if you want go as-is.
…pplied suggestions, reverted a visualization test to its original form
@nkanazawa1989 , I have added the suggestions :) Please see, if this is good enough :) |
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.
Thanks @MozammilQ for updating the conversion logic. New code seems more readable :)
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.
I know that this already merged, I was just taking a quick look through after see it in the git log this morning. I had a few quick comments and questions inline nothing huge and things that are easy to fix in a follow up PR.
"Definition of instruction %s is not found in the Qiskit namespace and " | ||
"GateConfig is not provided by the BackendConfiguration payload. " | ||
"Qiskit Gate model cannot be instantiated for this instruction and " | ||
"this instruction is silently excluded from the Target. " | ||
"Please add new gate class to Qiskit or provide GateConfig for this name.", |
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.
This isn't 100% accurate, the input instruction could be in the Qiskit namespace, but it also could have been user provided with custom_name_mapping
which allows end users to specify a custom name to gate object mapping as a dictionary input. Personally I'd have just warned with something like:
No gate definition for %s can be found and is being excluded from the generated target. You can use `custom_name_mapping` to provide a definition for this operation.
I probably would have used a RuntimeWarning
or a UserWarning
instead of logging a warning so it's a bit more visible.
add_delay: bool = True, | ||
filter_faulty: bool = True, |
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.
This is an API change and should be documented in an upgrade
note
add_delay: bool = True, | ||
filter_faulty: bool = True, |
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.
This is an api change and should be documented in the release notes.
.. note:: | ||
Passing in legacy objects like BackendProperties as properties and PulseDefaults | ||
as defaults will be deprecated in the future. |
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.
I would remove this from the docstring, the point at which we no longer support BackendProperties
and PulseDefaults
this converter function can be removed from qiskit. We're not at the point of deprecating the legacy interface though.
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.
Fair enough
elif name in gate_configs: | ||
this_config = gate_configs[name] | ||
params = list(map(Parameter, getattr(this_config, "parameters", []))) | ||
coupling_map = getattr(this_config, "coupling_map", []) | ||
inst_name_map[name] = Gate( | ||
name=name, | ||
num_qubits=len(coupling_map[0]) if coupling_map else 0, | ||
params=params, | ||
) |
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.
Is the assumption here that if a gate has some details definition in the configuration payload that something like PulseDefaults
will provide a calibration for it? My first thought here was that adding an opaque gate definition to the target is of little value because nothing will be able to generate a bespoke gate without a definition and people won't know what to do with it.
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.
Yes, you're absolutely right. But this is what exactly GateConfig model provides. In my understanding this just translates some opcode into Qiskit gate model, where the opcode (e.g. Qasm) doesn't have quantum definition and no optimization is necessary in quantum domain.
qubits = tuple(gate.qubits) | ||
if filter_faulty: | ||
if any(not properties.is_qubit_operational(qubit) for qubit in qubits): | ||
faulty_qubits = properties.faulty_qubits() |
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.
Using a list here causes the faulty qubit check below to be O(n^2)
is there a reason you changed this to a list?
if any(not properties.is_qubit_operational(qubit) for qubit in qubits): | ||
faulty_qubits = properties.faulty_qubits() | ||
|
||
for name in prop_name_map.keys(): |
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.
In general you don't need to use keys()
like this because the iter(dict)
will iterate over the keys already and this just creates a temporary object.
in_param = { | ||
"error": params["gate_error"][0] if "gate_error" in params else None, | ||
"duration": params["gate_length"][0] if "gate_length" in params else None, | ||
} | ||
inst_prop = InstructionProperties(**in_param) |
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.
Is there a reason you need to use an intermediate dictionary here? Wouldn't it create one less object if you just did:
in_param = { | |
"error": params["gate_error"][0] if "gate_error" in params else None, | |
"duration": params["gate_length"][0] if "gate_length" in params else None, | |
} | |
inst_prop = InstructionProperties(**in_param) | |
error = params["gate_error"][0] if "gate_error" in params else None | |
duration = params["gate_length"][0] if "gate_length" in params else None | |
inst_prop = InstructionProperties(error=error, duration=duration) |
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.
yeah this is copied from provider which I wrote where I needed to apply schema. This code is not really inefficient as you say.
Let me take a look (seems like this also introduced a bug) |
* This marks an initiative to replace the contents of method convert_to_target from qiskit.providers.backend_compat.py with contents of method target_from_server_data from qiskit_ibm_provider/utils/json_decoder.py * removed usage of supported_instructions from conf_*.json * fixed lint * added test, to check if the issue has been fixed * added release note * added suggestions and refactored code * removed argument deprecation, removed covert_to_target_legacy * refactor code * Added working add_delay argument in convert_to_target function, and removed source code for convert_to_target_legacy function from backend_compat.py. * refactor code * fixed lint * changed a test * altered release note * applied suggestions * add test * refactor code * altered handling of calibration data * docs * fix docs error * lint * refactor code * refactor code(removed inefficiencies and improved code legibility), applied suggestions, reverted a visualization test to its original form
* Followup - Add exception handling for the edge case in which a basis gate property is not reported - Cleanup docs - Replace logging with RuntimeWarning - Add more inline comments - Fix wrong typehints - Update handling of faulty qubits with set operation * bugfix + more warning message * Update reno * Add more check for filter option
* Followup - Add exception handling for the edge case in which a basis gate property is not reported - Cleanup docs - Replace logging with RuntimeWarning - Add more inline comments - Fix wrong typehints - Update handling of faulty qubits with set operation * bugfix + more warning message * Update reno * Add more check for filter option
Summary
This updates the logic of backend model up-conversion. The logic is highly motivated with the one in qiskit_ibm_provider which is
target_from_server_data
in qiskit_ibm_provider/utils/json_decoder.pyThe following code:
should produce this:
instead, it produces this:
Details and comments
The problem occurs here
I tried using convert_to_target() from qiskit/providers/fake_provider/utils/json_decoder.py but that also didn't solve the problem.
target_from_server_data() from qiskit_ibm_provider/utils/json_decoder.py does solve the problem, so I replaced the contents of convert_to_target() in qiskit/providers/backend_compat.py with the content of target_from_server_data().
Credit: @to24toro , has been kind enough to provide a helping hand here :)