-
Notifications
You must be signed in to change notification settings - Fork 105
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
iSWAP gate and Givens gate #304
Conversation
Hi Daria, Thanks for contributing. We’re definitely interested in contributions like this. One thing I spotted: A convenient iSWAP is however not there yet (know that, because people asked about it in the past :-) ). Have a nice weekend. |
src/tequila/circuit/gates.py
Outdated
|
||
generator = paulis.from_string(f"1.0*Y({first})X({second}) - 1.0*X({first})Y({second})") | ||
|
||
return GeneralizedRotation(angle=angle, control=control, generator=generator,) |
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 Givens Rotation is identical to a single-qubit excitation. Can you change the return to:
return QubitExcitation(target=[first,second], angle=angle, control=control, *args, **kwargs)
If done like this, then optimizations in compiling and gradients that are implemented in the QubitExcitation class are also used here.
Slightly different convention:
QubitExcitation generator: XY - YX while here you have YX-XY
If the sign difference matters, you can just switch the qubits in the call to the constrcutor:
return QubitExcitation(target=[second,first], angle=angle, control=control, *args, **kwargs)
src/tequila/circuit/gates.py
Outdated
""" | ||
|
||
generator = paulis.from_string(f"X({first})X({second}) + Y({first})Y({second})") | ||
return GeneralizedRotation(angle=power*(-np.pi/2), control=control, generator=generator, |
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.
Looks good!
One issue that will arise with gradient compilation:
The generator here has 3 distinct eigenvalues (+2,-2 and 0), so it is not directly shift-rule differentiable. One can however fix this by exploiting the fact that one of the eigenvalues is 0.
One can fix that in the following:
- write the generator as G = Gp + Gm, where Gp = G + P0 and Gm = G - P0 and P0 is the projector on the eigenspace with eigenvalue zero (in this case P0 = |00><00| + |11><11|)
Now both new generators are directly differentiable. If we know, that the wavefunction this gate is acting on has only real coefficients, the gradient compilation can be optimized further, this is why the assume_real
flag can be set. Ideally you just allow this here as well (either explicitly in the declaration, or implicitly via args, kwargs)
The details behind this procedure: https://arxiv.org/abs/2011.05938
fortunately, the qubit excitation class then contains all the necessary technology. We just need to make sure, that specific optimized compilation routines are not called.
p0 = tq.paulis.Projector("|00>") + tq.paulis.Projector("|11>")
p0 = P0.map_qubits({0:first, 1:second})
gate = QubitExcitationImpl(angle=angle, target=generator.qubits, generator=generator, p0=p0, assume_real=assume_real, control=control, compile_option="vanilla", *args, **kwargs)
return QCircuit.wrap_gate(gate)
... this should work (let me know if not)
@kottmanj Thank you for your extensive review. I have incorporated your comments into the last commit, let me know if you agree with those changes. |
To the best of my knowledge, the current code has no direct implementation for the
iSWAP
gateGivens
gateI have implemented them using
GeneralizedRotation
gates. I have written some test cases for both gates as well. Please let me know if these gates are of any interest to you and if you have further remarks/requests.