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