Skip to content
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

Remove condition/c_if, duration, and unit from instructions #13506

Merged
merged 92 commits into from
Feb 24, 2025

Conversation

mtreinish
Copy link
Member

@mtreinish mtreinish commented Dec 1, 2024

Summary

This commit removes the per instruction attributes for condition, duration, and unit. These attributes were deprecated in 1.3.0. Besides the label these attributes were the only mutable state for singleton instructions and removing them simplifies what needs to be tracked for instructions in both Python and rust. The associated methods and classes that were previously dependent on these attributes are also removed as they no longer serve a purpose. The removal of condition in particular removes a lot of logic from Qiskit especially from the transpiler because it was a something that needed to be checked outside of the normal data model for every operation.

This PR simplifies the representation of this extra mutable state in Rust by removing the ExtraInstructionAttributes struct and replacing it with a Option<Box<String>>. The Option<Box<String>> is used instead of the simpler Option<String> because this this reduces the size of the label field from 24 bytes for Option<String> to 8 bytes for Option<Box<String>> with an extra layer of pointer indirection and a second heap allocation. This will have runtime overhead when labels are set, but because the vast majority of operations don't set labels the tradeoff for optimizing for the None case makes more sense. Another option would have been to use Box<str> here which is the equivalent of Box<[u8]> (where String is the equivalent to Vec<u8>) and from a runtime memory tradeoff would be a better choice for this application if labels were commonly used as labels aren't growable. But that requires 16 bytes instead of 8 and we'd be wasting an additional 8 bytes for each instruction in the circuit which isn't worth the cost.

Details and comments

TODO:

  • Fix scheduling pass updates
  • Remove remaining c_if usage in tests (there's >200 instances of it still)
  • Fix any failing tests not caused by the above 2 (hard to see with ~300-400 failures)
  • Finish writing release notes
  • Do some tuning/profiling to see if we can optimize things a bit more after the removal

@mtreinish mtreinish added on hold Can not fix yet Changelog: API Change Include in the "Changed" section of the changelog Changelog: Removal Include in the Removed section of the changelog Rust This PR or issue is related to Rust code in the repository mod: transpiler Issues and PRs related to Transpiler mod: circuit Related to the core of the `QuantumCircuit` class or the circuit library labels Dec 1, 2024
@mtreinish mtreinish added this to the 2.0.0 milestone Dec 1, 2024
This commit removes the per instruction attributes for condition,
duration, and unit. These attributes were deprecated in 1.3.0. Besides
the label these attributes were the only mutable state for singleton
instructions and removing them simplifies what needs to be tracked for
instructions in both Python and rust. The associated methods and classes
that were previously dependent on these attributes are also removed as
they no longer serve a purpose. The removal of condition in particular
removes a lot of logic from Qiskit especially from the transpiler
because it was a something that needed to be checked outside of the
normal data model for every operation.

This PR simplifies the representation of this extra mutable state in
Rust by removing the `ExtraInstructionAttributes` struct and replacing
it with a `Option<Box<String>>`. The `Option<Box<String>>` is used
instead of the simpler `Option<String>` because this this reduces the
size of the label field from 24 bytes for `Option<String>` to 8 bytes
for `Option<Box<String>>` with an extra layer of pointer indirection
and a second heap allocation. This will have runtime overhead when
labels are set, but because the vast majority of operations don't set
labels the tradeoff for optimizing for the None case makes more sense.
Another option would have been to use `Box<str>` here which is the
equivalent of `Box<[u8]>` (where `String` is the equivalent to
`Vec<u8>`) and from a runtime memory tradeoff would be a better
choice for this application if labels were commonly used as labels
aren't growable. But that requires 16 bytes instead of 8 and we'd be
wasting an additional 8 bytes for each instruction in the circuit which
isn't worth the cost.
@nonhermitian
Copy link
Contributor

Is there a replacement method for getting circuit timing if duration is removed? It is somewhat critical to have a way to determine circuit timing for a variety of reasons.

@jakelishman
Copy link
Member

I pushed up a few commits, but right now, I think there's trouble in the scheduling transpiler passes, in that some of the logic around converting Delay's time units seems to be in the wrong place now (and tbh, I don't immediately understand how it was working in the 1.x series). I'll have a bit more of a look into that.

Copy link
Member

@jakelishman jakelishman left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

13b6814 simplifies the modifications to the scheduling passes, which pulls them back a bit more to what I'd expect. Somebody else ought to review that commit, though.

Since I hadn't last time, I looked through all the tests too. I think there's a couple that were maybe removed by accident, but not certain.

I'm still not wild about the stability around the scheduling passes suddenly needing InstructionDurations (or Target) in 2.0 when it wasn't necessary in 1.x. I get why we have to do that, and I guess I'm saying I'm ok to accept it as a break/exception to the deprecation-policy, but only really because we don't have a choice at this point, other than keeping around state that we really don't want to keep alive any longer.

Other than these last few comments, I'm ok to approve.

self.assertAlmostEqual(result.values[0], 0, places=1)
self.assertAlmostEqual(float(result.values[0]), -1.0, places=1)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should this have changed? I feel like it still ought to be averaging to 0. Maybe a bug in Aer?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It shouldn't have changed as the condition should be identical. It would either be an aer bug or an issue in the primitive implementation (since the BackendEstimatorV2 version didn't require any update). I opted to just roll will it here because this test will also be removed with the BackendEstimator v1 estimator implementation and the v2 tests didn't need any changes.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sounds like it must be a bug - I feel like we should either delete this test (and the sampler one) slightly early, or put a big comment on it saying that we're asserting something incorrect. I don't like merging a PR that encodes an incorrect test, even if we're expecting it to be ephemeral.

self.assertDictAlmostEqual(result.quasi_dists[0], {0: 0.5029296875, 1: 0.4970703125})
self.assertDictAlmostEqual(result.quasi_dists[0], {0: 0.021484375, 1: 0.978515625})
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This also looks incorrect now - maybe an Aer bug?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I did the same thing here as for the estimator implementation.

@jakelishman
Copy link
Member

My only remaining comment is about the buggy backend primitives V1 tests - I don't mind if we eagerly remove them or put in a comment explaining that they're bugged, but I don't want to merge a broken test, just out of principle.

Otherwise: somebody else should confirm that my commit 13b6814 is fine, and then I can approve.

@mtreinish
Copy link
Member Author

My only remaining comment is about the buggy backend primitives V1 tests - I don't mind if we eagerly remove them or put in a comment explaining that they're bugged, but I don't want to merge a broken test, just out of principle.

I'll remove them then, I have the PR removing the backend primitive v1 open already here: #13877 which deletes both test files in their entirety.

Otherwise: somebody else should confirm that my commit 13b6814 is fine, and then I can approve.

It looks fine to me, I think that pass will need more of a refactor pretty soon. The whole mutating the local durations object based on the dag doesn't really work after this PR and the removal of pulse, but for now it should be fine.

Two primitives tests were returning incorrect results after being
rewritten to use IfElseOp instead of c_if. This is likely pointing to a
bug in the primitive implementation or an aer bug. But since those
classes are deprecated and the tests will be removed as part of the
larger backend v1 primitive implementation removal in Qiskit#13877 anyway this
commit opts to just delete these tests now.
Copy link
Member

@jakelishman jakelishman left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for all the changes on this. Let's get this merged, and hopefully there's not too much of a tail afterwards. I suspect we'll at least need to port some changes over to qiskit-ibm-runtime in the scheduling passes.

@jakelishman jakelishman added this pull request to the merge queue Feb 24, 2025
@github-merge-queue github-merge-queue bot removed this pull request from the merge queue due to failed status checks Feb 24, 2025
@jakelishman jakelishman added this pull request to the merge queue Feb 24, 2025
@mtreinish mtreinish removed this pull request from the merge queue due to a manual request Feb 24, 2025
@mtreinish mtreinish added this pull request to the merge queue Feb 24, 2025
Merged via the queue into Qiskit:main with commit 6c7ee8f Feb 24, 2025
17 checks passed
@mtreinish mtreinish deleted the drop-instruction-dead-weight branch February 24, 2025 16:50
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Changelog: API Change Include in the "Changed" section of the changelog Changelog: Removal Include in the Removed section of the changelog mod: circuit Related to the core of the `QuantumCircuit` class or the circuit library mod: transpiler Issues and PRs related to Transpiler priority: high Rust This PR or issue is related to Rust code in the repository
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Require a target in the timeline drawer Deprecate propagate_condition argument in DAGCircuit substitutions
7 participants