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

Implement a N - qubit QFT with one line of code. #26

Closed
matt-lourens opened this issue May 21, 2023 · 7 comments
Closed

Implement a N - qubit QFT with one line of code. #26

matt-lourens opened this issue May 21, 2023 · 7 comments

Comments

@matt-lourens
Copy link
Owner

matt-lourens commented May 21, 2023

Summary

The Quantum Fourier Transform has nice symmetry in it's circuit representation, as seen here from Nielsen and Chuang Chapter 5:
image

This amends itself well to being implementable with HierarQcal. We will however need a new primitive operation called Qpivot which given a 2 qubit unitary, cycles though each qubit and connects it to one pivot qubit (pivot acts as target, more detail below). The gist of this issue is implementing the new Qpivot primitive and showcasing it's usage in the examples notebook with QFT, which I think we can do in essentially one line.

Example usage

It will go something like this:

N = 5
h_top = Qpivot(pattern="1*", mapping=u_h)
controlled_rs = Qpivot(pattern="1*", mapping=u_cr, share_weights=False)
hcr = h_top + controlled_rs
qft = Qinit(N)  + (hcr + Qmask("1*"))*(N)

The Qpivot primitive is very similar to the Qmask primitive so use that as a reference (see Qmask examples in quickstart.ipynb), and I'm happy to explain in more detail how Qmask works to make the development easier. Qpivot will receive a pattern string, where '1' indicates the pivot qubit and 0 the control. The star is a wild card which gets filled with '0''s based on the number of available qubits. 1* pivots to the top qubit, *1 to the bottom, *1* to the middle, 1*1*1 has 3 pivots which can be connected based on nearest neighbour or the normal cycle pattern, something similar is already implemented in Qmask which I can take you through. For one qubit unitaries (such as the h_top for the Hadamard) the unitary gets placed only on pivot qubits. You can ignore the N>2-qubit unitary case, I will implement that logic but it will be the same idea as Qmask.

Here's some examples of the directed graphs corresponding the pivot primitive (qubits are nodes and 2-qubit unitaries edges):

Pivot "1*" pattern on 8 qubits

pivot_1

Pivot "*1" pattern on 8 qubits

pivot_8

@Aaron-Robertson
Copy link

Sounds like a blast, I'd like to take this one @matt-lourens!

@matt-lourens
Copy link
Owner Author

That's Great, thanks @Aaron-Robertson!

Let me know if anything is unclear, I'm happy to elaborate more on the issue or package.

@Aaron-Robertson
Copy link

@matt-lourens I walked through the examples and code but I'm still not completely clear, so perhaps better we sync up! I'm happy to take notes while we do if you like, since I noticed a few TODOs around documenting Qmask.

@matt-lourens
Copy link
Owner Author

Hey @Aaron-Robertson sure thing, let's do call and sync up, are you free sometime tomorrow? I'm in SAST time, and can do a call the morning somewhere between 09:00 and 13:00. Let me know what time would work for you.

Qmask does a lot of things, so getting to grip with it does take time. The Qpivot will only relate to a small part of the Qmask functionality, specifically the Qmask functionality that generates edges for arity=2 mappings. The rest of Qmask you can essentially "ignore". So there won't be a Qunpivot nor a Qpivot_base. The reason being that Qpivot won't make any qubits unavailable, so there won't be qubits to make available again. I should've been more clear on what the relation to Qmask is, and that is only in the way that edges gets generated based on a pattern for 2 qubit unitaries.

The outline for Qpivot will look something like:

class Qpivot(Qmotif):
    """
    """

    def __init__(self, pattern="1*", **kwargs):
        # Initalize Qpivot, has a pattern attribute
        pass

    def __call__(self, Qc_l, *args, **kwargs):
        # Check if arity==2
            # Get pivot pattern function based on the logic from Qmask_base.get_mask_pattern_fn 
                # The relevant logic from Qmask_base.get_mask_pattern_fn is lines 731-753 (the if any("*") block)
            # Set source and pivot qubits by calling pivot pattern function
            # Generate edges based on connection type, nearest_cicle, nearest_tower, cycle
                # The logic of this will be similar to Qmask lines 849-881
                # You can ignore the other Qmask code, the true case  for the if on line 844 goes into the mask functionality that most mimics the qpivot one
            # If connection type is cycle use stride, step and offset to generate the edges
                # The stride
        return self

    def __eq__(self, other):
        # Equality check
        pass

I hope that makes things a bit clearer.

Stepping through the code:

u = Qunitary(V2, 0, 2)
hierq = Qinit(8) + Qmask("1*1*1", mapping=u)
circuit = hierq(backend="qiskit")
circuit.draw("mpl")


u = Qunitary(V2, 0, 2)
hierq = Qinit(8) + Qmask("*1", mapping=u)
circuit = hierq(backend="qiskit")
circuit.draw("mpl")

Should also help, specifically if you have a breakpoint on line 849 if self.connection_type == "nearest_circle": and check what happens based on different connection types, it might make things clearer. It is that logic of Qmask where edge generation is similar. The other part is the pattern string from 731-753 (the if any("*") block

@Aaron-Robertson
Copy link

Aaron-Robertson commented May 28, 2023

@matt-lourens That clarifies most of my concerns, so thanks! I can be available from 12-13, but will go ahead with the stub as provided. Fortunately all I'd done was use a find and replace on mask as a way to walk through the code. The only functionality I worked on was the pattern matching, which should work as desired (though we can discuss custom pivot functions-which I don't imagine we'll want based on that description-and base patterns). I'll push up the updates shortly, and look forward to chatting tomorrow!

@matt-lourens
Copy link
Owner Author

Hey @Aaron-Robertson 12 SAST works for me, do you have discord? I'm on the unitary fund server, you can reach me at: Mattx2#9155

@matt-lourens
Copy link
Owner Author

Fixed with #40

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 a pull request may close this issue.

2 participants