Qiskit / qiskit-metapackage

Qiskit is an open-source SDK for working with quantum computers at the level of circuits, algorithms, and application modules.
https://qiskit.org
Apache License 2.0
3.03k stars 750 forks source link

problem specific PQC ansatz for VQE #1630

Closed gatorwatt closed 1 year ago

gatorwatt commented 1 year ago

Hi there, was just working through the IBM Quantum Fall Challenge exercises and threw together an assembler for the "problem specific PQC" described by Matsuo et al (https://arxiv.org/pdf/2006.05643.pdf). I didn't see this in your docs anywhere, in case you might find handy please feel free to make use of following. Yeah had a good time going through the notebooks, organizers did a great job.

#here is an example of usage to derive a VQE model as function of number of qubits n:
model, theta, param_i = VQE_ansatz(n)
model.draw("mpl")

#____________________

def get_qmap(n):
    """
    qmap is a dictionary mapping between qubit addresses
    the reason am using this is because since VQE_ansatz applies recursion
    when the n=2 is assembled VQE_ansatz doesn't know how 
    to assign correct final address after taking into account n>2
    so we will first assemble this map based on the total n
    and then pass through recursion

    as an example, for n=4, this will return
    {0: 0,
     1: 1,
     4: 2,
     9: 3,
     2: 4,
     3: 5,
     5: 6,
     10: 7,
     6: 8,
     7: 9,
     8: 10,
     11: 11,
     12: 12,
     13: 13,
     14: 14,
     15: 15}
    """

    converted_list = list(range(n**2))

    for nn in range(2, n+1):

      for imap in range(nn-2):

          insert_at = (imap + 1) * nn - 1

          insert_value = (nn-1)**2 + imap

          converted_list.remove(insert_value)

          converted_list.insert(insert_at, insert_value)

    qmap = dict(zip(converted_list, list(range(n**2))))

    return qmap

def VQE_ansatz(n, circ=False, theta=False, param_i=0, qmap=False):
    """
    populates a VQE ansatz per the "method 4" described by Matsuo et al (arxiv 2006.05643)
    uses recursion to sequentially populate ansatz for n=2,3,4,...
    further detail in lab3 of Fall Quantum Challenge
    """

    # Define QuantumCircuit and ParameterVector size
    if circ is False:
        circ = QuantumCircuit(n**2)
    if theta is False:
        theta =  ParameterVector('theta',length=(n-1)*n//2)   #(n-1)*n)

    if qmap is False:
        qmap = get_qmap(n)

    if n>2:
        circ, theta, param_i = \
        VQE_ansatz(n-1, circ, theta, param_i, qmap)

        #_____
        #new parameterized

        x_target = (n-1)**2 + (n-2) + 1

        circ.x(qmap[x_target])

        i=0
        for param_target in range( (n-1)**2 + (n-2) + 2, n**2 ):

            circ.ry(theta[param_i],qmap[param_target])
            circ.cz( qmap[(param_target - 1)], qmap[param_target])
            circ.ry(-theta[param_i],qmap[param_target])
            circ.cx(qmap[param_target], qmap[(param_target - 1)] )

            param_i += 1

        #_____ 
        #new cswaps

        for i in range(n-1):

            for j in range(n-1):

                control_cswap_wire = (n-1)**2 + (n-1) + i

                if i == n-2:
                    if j == n-2:
                        # print("scenario b")
                        first_cswap_wire_target = (n-1)**2 - 1
                    else:
                        # print("scenario c")
                        first_cswap_wire_target = (n-2)**2 +j

                # else i != n-2 and j != n-2:
                else:
                    # print("scenario a")
                    first_cswap_wire_target = j*(j+1)+i

                second_cswap_wire_target = (n-1)**2 + j

                # print()
                # print("n = ", n)
                # print("i = ", i)
                # print("j = ", j)
                # print("control_cswap_wire", control_cswap_wire)
                # print("first_cswap_wire_target", first_cswap_wire_target)
                # print("second_cswap_wire_target", second_cswap_wire_target)

                circ.cswap( qmap[control_cswap_wire], qmap[first_cswap_wire_target], qmap[second_cswap_wire_target] )

    if n==2:

        x_target = qmap[0]

        circ.x(qmap[0])

        circ.ry(theta[param_i],qmap[1])
        circ.cz(qmap[0],qmap[1])
        circ.ry(-theta[param_i],qmap[1])
        circ.cx(qmap[1],qmap[0])

        circ.cx(qmap[1],qmap[2])
        circ.cx(qmap[0],qmap[3])

        param_i += 1

        return circ, theta, param_i

    return circ, theta, param_i
gatorwatt commented 1 year ago

After further benchmarking verses other scenarios presented in the exercise decided to withdraw. Hope this wasn't a distraction.