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

CNOT doesn't decompose to CNOT #5712

Closed
wants to merge 5 commits into from
Closed

CNOT doesn't decompose to CNOT #5712

wants to merge 5 commits into from

Conversation

lillian542
Copy link
Contributor

@lillian542 lillian542 commented May 17, 2024

Context:
Up to and including Pennylane 0.34, the CNOT gate raised a DecompositionUndefinedError in its decomposition method. We added some smart handling of decompositions for controlled operators that accidentally started decomposing CNOT into itself.

Description of the Change:
Make it so _decompose_pauli_x_based_no_control_values no longer provides a decomposition for CNOT (it currently just sees a controlled op with a base of PauliX, and decomposes to CNOT). The decomposition functions then follow another pathway and return another decomposition for CNOT.

Benefits:
This fringe but odd behaviour doesn't happen anymore

Possible Drawbacks:
I tested it by adding a check to assert_valid, maybe this problem is too much of an edge case to be in assert_valid. But with the controlled ops finding their own decompositions instead of having them hardcoded, I guess it could happen again 🤷‍♀️

Related GitHub Issues:
#5711

@lillian542
Copy link
Contributor Author

[sc-63619]

@lillian542 lillian542 marked this pull request as ready for review May 17, 2024 19:27
Copy link
Contributor

@dwierichs dwierichs left a comment

Choose a reason for hiding this comment

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

Thanks @lillian542, this looks good to me! Good catch :)

I just had a tiny suggestion, would ask to remove a print line, and wanted to confirm I understand the background correctly with a question :)

edit: Actually, this change might warrant a breaking change entry in the changelog, given the "failing" tape expansion tests and that CNOTs are omnipresent in standard circuits.

*qml.CY(wires=[1, 4]).decomposition(),
*qml.CZ(wires=[1, 0]).decomposition(),
qml.PauliX(wires=1),
]
assert len(tape) == 9
expanded = tape.expand(stop_at=lambda obj: not isinstance(obj, Controlled))
print(expanded.circuit)
Copy link
Contributor

Choose a reason for hiding this comment

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

Suggested change
print(expanded.circuit)

assert len(tape.operations) == 10
assert all(o.name in {"CNOT", "CRX", "Toffoli"} for o in tape.operations)
assert len(tape.operations) == 12
assert all(o.name in {"ControlledPhaseShift", "CRX", "Toffoli"} for o in tape.operations)
Copy link
Contributor

Choose a reason for hiding this comment

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

Just to make sure I understand: The requirement for a decomposition is not to imply any ordering of "complex gates" to "simpler gates", but just should allow us to keep decomposing until external stopping criteria (like those of a device) trigger? :)

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Exactly!

@@ -56,6 +56,9 @@ def _check_decomposition(op):
expand = op.expand()

assert isinstance(decomp, list), "decomposition must be a list"
assert op.__class__ not in [
decomp_op.__class__ for decomp_op in decomp
], "an operator should not be included in its own decomposition"
Copy link
Contributor

Choose a reason for hiding this comment

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

I actually would have expected some other operation popping up to have this bug here :D

Comment on lines +59 to +61
assert op.__class__ not in [
decomp_op.__class__ for decomp_op in decomp
], "an operator should not be included in its own decomposition"
Copy link
Contributor

Choose a reason for hiding this comment

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

Could do

Suggested change
assert op.__class__ not in [
decomp_op.__class__ for decomp_op in decomp
], "an operator should not be included in its own decomposition"
assert op.__class__ not in {
decomp_op.__class__ for decomp_op in decomp
}, "an operator should not be included in its own decomposition"

@lillian542
Copy link
Contributor Author

edit: Actually, this change might warrant a breaking change entry in the changelog, given the "failing" tape expansion tests and that CNOTs are omnipresent in standard circuits.

Agreed, I want to bring this up in stand up tomorrow and make sure it's something we actually want (I think it is, just want to confirm). Hopefully most people are decomposing in ways that include CNOT as a supported op and almost no one will notice.

But it could be between this and max_expansion=10 in the old device API that someone somewhere is decomposing CNOT into CNOT 10 times and then proceeding 😅 And that person will be surprised when all the CNOTs disappear from their circuits.

@trbromley
Copy link
Contributor

So just to summarise our discussion in the standup, here we are effectively reverting to behaviour in Q1?

@lillian542
Copy link
Contributor Author

So just to summarise our discussion in the standup, here we are effectively reverting to behaviour in Q1?

Yes - may or may not get back to this until next iteration, but the plan is to see what it used to do before we made Controlled decompositions smarter and it accidentally started doing this. And then go back to that behaviour.

@lillian542 lillian542 changed the base branch from master to v0.37.0-rc0 July 4, 2024 20:45
@astralcai astralcai deleted the branch v0.37.0-rc0 July 9, 2024 13:37
@astralcai astralcai closed this Jul 9, 2024
@trbromley
Copy link
Contributor

Is this to be reopened later on?

@lillian542
Copy link
Contributor Author

Oops! I forgot to change the target branch, and this happens when the target branch is deleted. It also happened for one of Matthew's PRs last time I was managing the release, and I think he had to re-create it, we weren't able to re-open it. But we can open a new PR from the same branch.

@lillian542
Copy link
Contributor Author

Now re-opened as #6039

@trbromley trbromley deleted the cnot-decomp branch July 25, 2024 14:55
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants