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

iSWAP gate and Givens gate #304

Merged
merged 6 commits into from
Sep 14, 2023
Merged

Conversation

dariavh
Copy link
Contributor

@dariavh dariavh commented Aug 18, 2023

To the best of my knowledge, the current code has no direct implementation for the

  • iSWAP gate $\exp(i\frac{\pi}{4}(X \otimes X + Y \otimes Y))$
  • Givens gate $\exp(-i \frac{\theta}{2} (Y \otimes X - X \otimes Y))$

I 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.

@kottmanj
Copy link
Collaborator

Hi Daria, Thanks for contributing. We’re definitely interested in contributions like this.
I’m currently on vacation with marginal internet access and won’t be able to go over the code before September. It does however look good on first glance.

One thing I spotted:
I think the Givens gate is the same as “QubitExcitation” with target=[first,second]. Makes still sense to have it as an alias though. You can however then replace the GeneralizedRotation with the corresponding call to QubitExcitation(….).

A convenient iSWAP is however not there yet (know that, because people asked about it in the past :-) ).
Need to check one or two things with the GeneralizedRotation definitions in order to make sure that gradient building will work as expected. I’ll provide more details in ~1.5 weeks when I’m back.

Have a nice weekend.


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,)
Copy link
Collaborator

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)

"""

generator = paulis.from_string(f"X({first})X({second}) + Y({first})Y({second})")
return GeneralizedRotation(angle=power*(-np.pi/2), control=control, generator=generator,
Copy link
Collaborator

@kottmanj kottmanj Aug 30, 2023

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)

@dariavh
Copy link
Contributor Author

dariavh commented Sep 11, 2023

@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.

@kottmanj kottmanj merged commit 521e3ce into tequilahub:devel Sep 14, 2023
16 checks passed
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.

2 participants