TeamGraphix / graphix

measurement-based quantum computing (MBQC) compiler and simulator
https://graphix.readthedocs.io
Apache License 2.0
55 stars 20 forks source link

Unitary from pattern #104

Open FlorianFuerrutter opened 7 months ago

FlorianFuerrutter commented 7 months ago

Describe the feature you'd like

Hey all, I'm interested if there is any (efficient) way to get the unitary implemented from a given pattern. I did not find any direct function but I think this could be done easily if one can set the input state arbitrarily (issue #53) and check for flow of a pattern.

Additional context

I would propose a (pseudo) code in that direction:

def get_unitary_from_pattern(pattern):

    # check if given pattern has flow, i.e. it implements indeed a unitary
    assert has_flow(pattern)

    # num_qubits .. defined via input/ouput nodes
    assert pattern.num_input_nodes == pattern.num_output_nodes

    num_qubits = pattern.num_input_nodes
    N          = 2**num_qubits

    #----- get unitary -----
    # do <i|U|j>=U_ij, where |n>=(0, .., 1, .., 0) std-basis
    # maybe the lib (tensornetwork) allows a more efficient way?

    U = np.zeros((N, N), dtype=np.complex128)

    for j in range(N): #can be async

        # set |j> input
        state_j    = np.zeros((N), dtype=np.complex128) 
        state_j[j] = 1
        pattern.set_input(state_j)

        # get matrix elements
        tn        = pattern.simulate_pattern(backend='tensornetwork')
        state_U_j = tn.to_statevector()

        U[:, j] = state_U_j

        #same as
        #for i in range(N): U[i, j] = state_U_j[i]

    return U

Maybe there is a better way to do this? Maybe even with the current code base?

shinich1 commented 7 months ago

Hey, thanks for the suggestion. Direct unitary extraction from a pattern would certainly be a good feature (we don't have that yet)!

For pattens with flow (only XY-plane measurements), it might be easier to directly translate into a gate network with CZ (edges connecting different flow paths) and

J(\alpha) = 
\begin{pmatrix} 
1 & e^{i\alpha} \\  
1 & -e^{i\alpha} 
\end{pmatrix}

(for XY-plane measurements with angle $\alpha$ along flow paths) gates and work out the unitary directly. For pattens with gflow, as you suggest, it's likely best to do simulations. TN simulation without inputs may give you the unitary (if memory allows).

cc: @masa10-f - would you agree or not? lmk what you think.

masa10-f commented 7 months ago

Thanks for the good comments! @shinich1 @FlorianFuerrutter

As far as I understand, direct construction from tensornetwork seems to be the most efficient method, no matter the type of flow(causal flow / generalize flow / pauli flow). First off, we create a tensornetwork by turning each measurement command into its tensor equivalent(e.g. N -> |+>, E -> 4-rank CZ tensor, M -> projection vector). Then, we contract all the inner edges. After that, we end up with a 2n-rank tensor, which can be reshaped into an n-qubit Unitary matrix. In this approach, we don't have to compute each matrix element one by one; we get them all in one go.

Regarding the implementation, we'll need to modify tensornet.py. It is not hard but may need some tensornetwork know-how.

If you're just looking at patterns with causal flow, @shinich1 's idea is pretty straightforward. We can apply the same techniques used in various quantum circuit libraries.

Just a reminder, the existence of Pauli flow is the weakest condition of Unitary embedding for a given pattern. So what we have to check here is pauli flow :)